mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +00:00 
			
		
		
		
	Generalize the SpinLock and move it to AK.
Add a separate lock to protect the VFS. I think this might be a good idea. I'm not sure it's a good approach though. I'll fiddle with it as I go along. It's really fun to figure out all these things on my own.
This commit is contained in:
		
							parent
							
								
									e4bfcd2346
								
							
						
					
					
						commit
						018da1be11
					
				
					 11 changed files with 88 additions and 203 deletions
				
			
		
							
								
								
									
										54
									
								
								AK/Lock.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								AK/Lock.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "Types.h" | ||||||
|  | 
 | ||||||
|  | namespace AK { | ||||||
|  | 
 | ||||||
|  | static inline dword CAS(volatile dword* mem, dword newval, dword oldval) | ||||||
|  | { | ||||||
|  |     dword ret; | ||||||
|  |     asm volatile( | ||||||
|  |         "cmpxchgl %2, %1" | ||||||
|  |         :"=a"(ret), "=m"(*mem) | ||||||
|  |         :"r"(newval), "m"(*mem), "0"(oldval)); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class SpinLock { | ||||||
|  | public: | ||||||
|  |     SpinLock() { } | ||||||
|  |     ~SpinLock() { unlock(); } | ||||||
|  | 
 | ||||||
|  |     void lock() | ||||||
|  |     { | ||||||
|  |         for (;;) { | ||||||
|  |             if (CAS(&m_lock, 1, 0) == 1) | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void unlock() | ||||||
|  |     { | ||||||
|  |         // barrier();
 | ||||||
|  |         m_lock = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     volatile dword m_lock { 0 }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class Locker { | ||||||
|  | public: | ||||||
|  |     explicit Locker(SpinLock& l) : m_lock(l) { m_lock.lock(); } | ||||||
|  |     ~Locker() { unlock(); } | ||||||
|  |     void unlock() { m_lock.unlock(); } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     SpinLock& m_lock; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | using AK::SpinLock; | ||||||
|  | using AK::Locker; | ||||||
|  | 
 | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| #include "Task.h" | #include "Task.h" | ||||||
| #include "Syscall.h" | #include "Syscall.h" | ||||||
| #include "Console.h" | #include "Console.h" | ||||||
|  | #include <AK/Lock.h> | ||||||
| 
 | 
 | ||||||
| extern "C" void syscall_entry(); | extern "C" void syscall_entry(); | ||||||
| extern "C" void syscall_ISR(); | extern "C" void syscall_ISR(); | ||||||
|  | @ -38,72 +39,6 @@ asm( | ||||||
|     "    iret\n" |     "    iret\n" | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| static inline dword CAS(dword* mem, dword newval, dword oldval) |  | ||||||
| { |  | ||||||
|     dword ret; |  | ||||||
|     asm volatile( |  | ||||||
|         "cmpxchgl %2, %1" |  | ||||||
|         :"=a"(ret), "=m"(*mem) |  | ||||||
|         :"r"(newval), "m"(*mem), "0"(oldval)); |  | ||||||
|     return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class SpinLock { |  | ||||||
| public: |  | ||||||
|     SpinLock() |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ~SpinLock() |  | ||||||
|     { |  | ||||||
|         unlock(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void lock() |  | ||||||
|     { |  | ||||||
|         volatile dword count = 0; |  | ||||||
|         for (;;) { |  | ||||||
|             if (CAS(&m_lock, 1, 0) == 1) |  | ||||||
|                 return; |  | ||||||
|             ++count; |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
|         if (count) |  | ||||||
|             kprintf("waited %u in %s\n",count, current->name().characters()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void unlock() |  | ||||||
|     { |  | ||||||
|         // barrier();
 |  | ||||||
|         m_lock = 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     dword m_lock { 0 }; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class Locker { |  | ||||||
| public: |  | ||||||
|     explicit Locker(SpinLock& l) |  | ||||||
|         : m_lock(l) |  | ||||||
|     { |  | ||||||
|         m_lock.lock(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ~Locker() |  | ||||||
|     { |  | ||||||
|         unlock(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void unlock() |  | ||||||
|     { |  | ||||||
|         m_lock.unlock(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     SpinLock& m_lock; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| namespace Syscall { | namespace Syscall { | ||||||
| 
 | 
 | ||||||
| static SpinLock* s_lock; | static SpinLock* s_lock; | ||||||
|  |  | ||||||
|  | @ -494,28 +494,6 @@ bool scheduleNewTask() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void drawSchedulerBanner(Task& task) |  | ||||||
| { |  | ||||||
|     return; |  | ||||||
|     // FIXME: We need a kernel lock to do stuff like this :(
 |  | ||||||
|     //return;
 |  | ||||||
|     auto c = vga_get_cursor(); |  | ||||||
|     auto a = vga_get_attr(); |  | ||||||
|     vga_set_cursor(0, 50); |  | ||||||
|     vga_set_attr(0x20); |  | ||||||
|     kprintf("          "); |  | ||||||
|     kprintf("          "); |  | ||||||
|     kprintf("          "); |  | ||||||
|     vga_set_cursor(0, 50); |  | ||||||
|     kprintf("pid: %u ", task.pid()); |  | ||||||
|     vga_set_cursor(0, 58); |  | ||||||
|     kprintf("%s", task.name().characters()); |  | ||||||
|     vga_set_cursor(0, 65); |  | ||||||
|     kprintf("eip: %p", task.tss().eip); |  | ||||||
|     vga_set_attr(a); |  | ||||||
|     vga_set_cursor(c); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool contextSwitch(Task* t) | static bool contextSwitch(Task* t) | ||||||
| { | { | ||||||
|     //kprintf("c_s to %s (same:%u)\n", t->name().characters(), current == t);
 |     //kprintf("c_s to %s (same:%u)\n", t->name().characters(), current == t);
 | ||||||
|  | @ -573,7 +551,6 @@ static bool contextSwitch(Task* t) | ||||||
|     tssDescriptor.type = 11; // Busy TSS
 |     tssDescriptor.type = 11; // Busy TSS
 | ||||||
| 
 | 
 | ||||||
|     flushGDT(); |     flushGDT(); | ||||||
|     drawSchedulerBanner(*t); |  | ||||||
| 
 | 
 | ||||||
|     t->didSchedule(); |     t->didSchedule(); | ||||||
|     return true; |     return true; | ||||||
|  |  | ||||||
|  | @ -33,21 +33,14 @@ byte vga_get_attr() | ||||||
| 
 | 
 | ||||||
| void vga_init() | void vga_init() | ||||||
| { | { | ||||||
|     DWORD i; |  | ||||||
| 
 |  | ||||||
|     current_attr = 0x07; |     current_attr = 0x07; | ||||||
|     vga_mem = (BYTE *)0xb8000; |     vga_mem = (byte*)0xb8000; | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < (80 * 24); ++i) { |     for (word i = 0; i < (80 * 25); ++i) { | ||||||
|         vga_mem[i*2] = ' '; |         vga_mem[i*2] = ' '; | ||||||
|         vga_mem[i*2 + 1] = 0x07; |         vga_mem[i*2 + 1] = 0x07; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Fill the bottom line with blue.
 |  | ||||||
|     for (i = (80 * 24); i < (80 * 25); ++i) { |  | ||||||
|         vga_mem[i*2] = ' '; |  | ||||||
|         vga_mem[i*2 + 1] = 0x17; |  | ||||||
|     } |  | ||||||
|     vga_set_cursor(0); |     vga_set_cursor(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -95,23 +95,6 @@ void clock_handle() | ||||||
|     current->tss().cs = regs.cs; |     current->tss().cs = regs.cs; | ||||||
|     current->tss().eflags = regs.eflags; |     current->tss().eflags = regs.eflags; | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
|     BYTE a = vga_get_attr(); |  | ||||||
|     WORD foo = vga_get_cursor(); |  | ||||||
| 
 |  | ||||||
|     vga_set_attr(0x50); |  | ||||||
|     vga_set_cursor(0); |  | ||||||
| 
 |  | ||||||
|     kprintf("\n\n"); |  | ||||||
|     kprintf("Task %u interrupted at %x             \n", current->pid(), regs.eip ); |  | ||||||
|     kprintf("EAX=%x EBX=%x ECX=%x EDX=%x           \n", regs.eax, regs.ebx, regs.ecx, regs.edx); |  | ||||||
|     kprintf("ESI=%x EDI=%x EBP=%x ESP=%x           \n", regs.esi, regs.edi, regs.ebp, regs.esp); |  | ||||||
|     kprintf("FLAGS=%x", regs.eflags); |  | ||||||
| 
 |  | ||||||
|     vga_set_cursor(foo); |  | ||||||
|     vga_set_attr(a); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     // Compute task ESP.
 |     // Compute task ESP.
 | ||||||
|     // Add 12 for CS, EIP, EFLAGS (interrupt mechanic)
 |     // Add 12 for CS, EIP, EFLAGS (interrupt mechanic)
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -32,53 +32,6 @@ | ||||||
| //#define TEST_ELF_LOADER
 | //#define TEST_ELF_LOADER
 | ||||||
| //#define TEST_CRASHY_USER_PROCESSES
 | //#define TEST_CRASHY_USER_PROCESSES
 | ||||||
| 
 | 
 | ||||||
| static void motd_main() NORETURN; |  | ||||||
| static void motd_main() |  | ||||||
| { |  | ||||||
|     kprintf("Hello in motd_main!\n"); |  | ||||||
|     int fd = Userspace::open("/test.asm"); |  | ||||||
|     kprintf("motd: fd=%d\n", fd); |  | ||||||
|     ASSERT(fd != -1); |  | ||||||
|     DO_SYSCALL_A3(0x2000, 1, 2, 3); |  | ||||||
|     kprintf("getuid(): %u\n", Userspace::getuid()); |  | ||||||
|     auto buffer = DataBuffer::createUninitialized(33); |  | ||||||
|     memset(buffer->data(), 0, buffer->length()); |  | ||||||
|     int nread = Userspace::read(fd, buffer->data(), buffer->length() - 1); |  | ||||||
|     kprintf("read(): %d\n", nread); |  | ||||||
|     buffer->data()[nread] = 0; |  | ||||||
|     kprintf("read(): '%s'\n", buffer->data()); |  | ||||||
|     for (;;) { |  | ||||||
|         //kill(4, 5);
 |  | ||||||
|         sleep(1 * TICKS_PER_SECOND); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void syscall_test_main() NORETURN; |  | ||||||
| static void syscall_test_main() |  | ||||||
| { |  | ||||||
|     kprintf("Hello in syscall_test_main!\n"); |  | ||||||
|     for (;;) { |  | ||||||
|         Userspace::getuid(); |  | ||||||
| //        Userspace::yield();
 |  | ||||||
|         //kprintf("getuid(): %u\n", Userspace::getuid());
 |  | ||||||
|         sleep(1 * TICKS_PER_SECOND); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void user_main() NORETURN; |  | ||||||
| static void user_main() |  | ||||||
| { |  | ||||||
|     DO_SYSCALL_A3(0x3000, 2, 3, 4); |  | ||||||
|     // Crash ourselves!
 |  | ||||||
|     char* x = reinterpret_cast<char*>(0xbeefbabe); |  | ||||||
|     *x = 1; |  | ||||||
|     HANG; |  | ||||||
|     for (;;) { |  | ||||||
|         // nothing?
 |  | ||||||
|         Userspace::sleep(1 * TICKS_PER_SECOND); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| system_t system; | system_t system; | ||||||
| 
 | 
 | ||||||
| void banner() | void banner() | ||||||
|  | @ -192,10 +145,7 @@ static void init_stage2() | ||||||
| 
 | 
 | ||||||
|     auto* shTask = Task::create("/bin/sh", (uid_t)100, (gid_t)100); |     auto* shTask = Task::create("/bin/sh", (uid_t)100, (gid_t)100); | ||||||
| 
 | 
 | ||||||
|     //new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
 |     banner(); | ||||||
|     //new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
 |  | ||||||
| 
 |  | ||||||
|     kprintf("init stage2 is done!\n"); |  | ||||||
| 
 | 
 | ||||||
| #if 0 | #if 0 | ||||||
|     // It would be nice to exit this process, but right now it instantiates all kinds of things.
 |     // It would be nice to exit this process, but right now it instantiates all kinds of things.
 | ||||||
|  |  | ||||||
|  | @ -1,36 +0,0 @@ | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "types.h" |  | ||||||
| 
 |  | ||||||
| extern "C" { |  | ||||||
| 
 |  | ||||||
| inline dword syscall_a0(dword function) |  | ||||||
| { |  | ||||||
|     dword result; |  | ||||||
|     asm volatile("int $0x80":"=a"(result):"a"(function)); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline dword syscall_a1(dword function, dword arg1) |  | ||||||
| { |  | ||||||
|     dword result; |  | ||||||
|     asm volatile("int $0x80":"=a"(result):"a"(function),"d"(arg1)); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline dword syscall_a2(dword function, dword arg1, dword arg2) |  | ||||||
| { |  | ||||||
|     dword result; |  | ||||||
|     asm volatile("int $0x80":"=a"(result):"a"(function),"d"(arg1),"c"(arg2)); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline dword syscall_a3(dword function, dword arg1, dword arg2, dword arg3) |  | ||||||
| { |  | ||||||
|     dword result; |  | ||||||
|     asm volatile("int $0x80":"=a"(result):"a"(function),"d"(arg1),"c"(arg2),"b"(arg3)); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
|  | @ -24,6 +24,8 @@ bool additionWouldOverflow(Unix::off_t a, Unix::off_t b) | ||||||
| 
 | 
 | ||||||
| int FileHandle::stat(Unix::stat* buffer) | int FileHandle::stat(Unix::stat* buffer) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     if (!m_vnode) |     if (!m_vnode) | ||||||
|         return -EBADF; |         return -EBADF; | ||||||
| 
 | 
 | ||||||
|  | @ -49,6 +51,8 @@ int FileHandle::stat(Unix::stat* buffer) | ||||||
| 
 | 
 | ||||||
| Unix::off_t FileHandle::seek(Unix::off_t offset, int whence) | Unix::off_t FileHandle::seek(Unix::off_t offset, int whence) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     if (!m_vnode) |     if (!m_vnode) | ||||||
|         return -EBADF; |         return -EBADF; | ||||||
| 
 | 
 | ||||||
|  | @ -91,6 +95,8 @@ Unix::off_t FileHandle::seek(Unix::off_t offset, int whence) | ||||||
| 
 | 
 | ||||||
| Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count) | Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     if (m_vnode->isCharacterDevice()) { |     if (m_vnode->isCharacterDevice()) { | ||||||
|         // FIXME: What should happen to m_currentOffset?
 |         // FIXME: What should happen to m_currentOffset?
 | ||||||
|         return m_vnode->characterDevice()->read(buffer, count); |         return m_vnode->characterDevice()->read(buffer, count); | ||||||
|  | @ -102,6 +108,8 @@ Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count) | ||||||
| 
 | 
 | ||||||
| ByteBuffer FileHandle::readEntireFile() | ByteBuffer FileHandle::readEntireFile() | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     if (m_vnode->isCharacterDevice()) { |     if (m_vnode->isCharacterDevice()) { | ||||||
|         auto buffer = ByteBuffer::createUninitialized(1024); |         auto buffer = ByteBuffer::createUninitialized(1024); | ||||||
|         Unix::ssize_t nread = m_vnode->characterDevice()->read(buffer.pointer(), buffer.size()); |         Unix::ssize_t nread = m_vnode->characterDevice()->read(buffer.pointer(), buffer.size()); | ||||||
|  |  | ||||||
|  | @ -20,9 +20,18 @@ VirtualFileSystem& VirtualFileSystem::the() | ||||||
|     return *s_the; |     return *s_the; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static SpinLock* s_vfsLock; | ||||||
|  | 
 | ||||||
|  | SpinLock& VirtualFileSystem::lock() | ||||||
|  | { | ||||||
|  |     ASSERT(s_vfsLock); | ||||||
|  |     return *s_vfsLock; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void VirtualFileSystem::initializeGlobals() | void VirtualFileSystem::initializeGlobals() | ||||||
| { | { | ||||||
|     s_the = nullptr; |     s_the = nullptr; | ||||||
|  |     s_vfsLock = new SpinLock; | ||||||
|     FileSystem::initializeGlobals(); |     FileSystem::initializeGlobals(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -336,6 +345,8 @@ void VirtualFileSystem::listDirectoryRecursively(const String& path) | ||||||
| 
 | 
 | ||||||
| bool VirtualFileSystem::touch(const String& path) | bool VirtualFileSystem::touch(const String& path) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     auto inode = resolvePath(path); |     auto inode = resolvePath(path); | ||||||
|     if (!inode.isValid()) |     if (!inode.isValid()) | ||||||
|         return false; |         return false; | ||||||
|  | @ -344,6 +355,8 @@ bool VirtualFileSystem::touch(const String& path) | ||||||
| 
 | 
 | ||||||
| OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     auto inode = resolvePath(path); |     auto inode = resolvePath(path); | ||||||
|     if (!inode.isValid()) |     if (!inode.isValid()) | ||||||
|         return nullptr; |         return nullptr; | ||||||
|  | @ -355,6 +368,8 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | ||||||
| 
 | 
 | ||||||
| OwnPtr<FileHandle> VirtualFileSystem::create(const String& path) | OwnPtr<FileHandle> VirtualFileSystem::create(const String& path) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     // FIXME: Do the real thing, not just this fake thing!
 |     // FIXME: Do the real thing, not just this fake thing!
 | ||||||
|     (void) path; |     (void) path; | ||||||
|     m_rootNode->fileSystem()->createInode(m_rootNode->fileSystem()->rootInode(), "empty", 0100644, 0); |     m_rootNode->fileSystem()->createInode(m_rootNode->fileSystem()->rootInode(), "empty", 0100644, 0); | ||||||
|  | @ -363,6 +378,8 @@ OwnPtr<FileHandle> VirtualFileSystem::create(const String& path) | ||||||
| 
 | 
 | ||||||
| OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path) | OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path) | ||||||
| { | { | ||||||
|  |     Locker locker(VirtualFileSystem::lock()); | ||||||
|  | 
 | ||||||
|     // FIXME: Do the real thing, not just this fake thing!
 |     // FIXME: Do the real thing, not just this fake thing!
 | ||||||
|     (void) path; |     (void) path; | ||||||
|     m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755); |     m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755); | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #include <AK/RetainPtr.h> | #include <AK/RetainPtr.h> | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
| #include <AK/Vector.h> | #include <AK/Vector.h> | ||||||
|  | #include <AK/Lock.h> | ||||||
| #include "InodeIdentifier.h" | #include "InodeIdentifier.h" | ||||||
| #include "Limits.h" | #include "Limits.h" | ||||||
| 
 | 
 | ||||||
|  | @ -15,6 +16,7 @@ class FileSystem; | ||||||
| class VirtualFileSystem { | class VirtualFileSystem { | ||||||
| public: | public: | ||||||
|     static void initializeGlobals(); |     static void initializeGlobals(); | ||||||
|  |     static SpinLock& lock(); | ||||||
| 
 | 
 | ||||||
|     struct Node { |     struct Node { | ||||||
|         InodeIdentifier inode; |         InodeIdentifier inode; | ||||||
|  |  | ||||||
|  | @ -21,6 +21,8 @@ int main(int c, char** v) | ||||||
|     if (c >= 2) |     if (c >= 2) | ||||||
|         filename = v[1]; |         filename = v[1]; | ||||||
| 
 | 
 | ||||||
|  |     VirtualFileSystem::initializeGlobals(); | ||||||
|  | 
 | ||||||
|     VirtualFileSystem vfs; |     VirtualFileSystem vfs; | ||||||
| 
 | 
 | ||||||
|     auto zero = make<ZeroDevice>(); |     auto zero = make<ZeroDevice>(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling