mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:12:44 +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 "Syscall.h" | ||||
| #include "Console.h" | ||||
| #include <AK/Lock.h> | ||||
| 
 | ||||
| extern "C" void syscall_entry(); | ||||
| extern "C" void syscall_ISR(); | ||||
|  | @ -38,72 +39,6 @@ asm( | |||
|     "    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 { | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     //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
 | ||||
| 
 | ||||
|     flushGDT(); | ||||
|     drawSchedulerBanner(*t); | ||||
| 
 | ||||
|     t->didSchedule(); | ||||
|     return true; | ||||
|  |  | |||
|  | @ -33,22 +33,15 @@ byte vga_get_attr() | |||
| 
 | ||||
| void vga_init() | ||||
| { | ||||
|     DWORD i; | ||||
| 
 | ||||
|     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 + 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); | ||||
| } | ||||
| 
 | ||||
| WORD vga_get_cursor() | ||||
|  |  | |||
|  | @ -95,23 +95,6 @@ void clock_handle() | |||
|     current->tss().cs = regs.cs; | ||||
|     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.
 | ||||
|     // Add 12 for CS, EIP, EFLAGS (interrupt mechanic)
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,53 +32,6 @@ | |||
| //#define TEST_ELF_LOADER
 | ||||
| //#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; | ||||
| 
 | ||||
| void banner() | ||||
|  | @ -192,10 +145,7 @@ static void init_stage2() | |||
| 
 | ||||
|     auto* shTask = Task::create("/bin/sh", (uid_t)100, (gid_t)100); | ||||
| 
 | ||||
|     //new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
 | ||||
|     //new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
 | ||||
| 
 | ||||
|     kprintf("init stage2 is done!\n"); | ||||
|     banner(); | ||||
| 
 | ||||
| #if 0 | ||||
|     // 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) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     if (!m_vnode) | ||||
|         return -EBADF; | ||||
| 
 | ||||
|  | @ -49,6 +51,8 @@ int FileHandle::stat(Unix::stat* buffer) | |||
| 
 | ||||
| Unix::off_t FileHandle::seek(Unix::off_t offset, int whence) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     if (!m_vnode) | ||||
|         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) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     if (m_vnode->isCharacterDevice()) { | ||||
|         // FIXME: What should happen to m_currentOffset?
 | ||||
|         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() | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     if (m_vnode->isCharacterDevice()) { | ||||
|         auto buffer = ByteBuffer::createUninitialized(1024); | ||||
|         Unix::ssize_t nread = m_vnode->characterDevice()->read(buffer.pointer(), buffer.size()); | ||||
|  |  | |||
|  | @ -20,9 +20,18 @@ VirtualFileSystem& VirtualFileSystem::the() | |||
|     return *s_the; | ||||
| } | ||||
| 
 | ||||
| static SpinLock* s_vfsLock; | ||||
| 
 | ||||
| SpinLock& VirtualFileSystem::lock() | ||||
| { | ||||
|     ASSERT(s_vfsLock); | ||||
|     return *s_vfsLock; | ||||
| } | ||||
| 
 | ||||
| void VirtualFileSystem::initializeGlobals() | ||||
| { | ||||
|     s_the = nullptr; | ||||
|     s_vfsLock = new SpinLock; | ||||
|     FileSystem::initializeGlobals(); | ||||
| } | ||||
| 
 | ||||
|  | @ -336,6 +345,8 @@ void VirtualFileSystem::listDirectoryRecursively(const String& path) | |||
| 
 | ||||
| bool VirtualFileSystem::touch(const String& path) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     auto inode = resolvePath(path); | ||||
|     if (!inode.isValid()) | ||||
|         return false; | ||||
|  | @ -344,6 +355,8 @@ bool VirtualFileSystem::touch(const String& path) | |||
| 
 | ||||
| OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     auto inode = resolvePath(path); | ||||
|     if (!inode.isValid()) | ||||
|         return nullptr; | ||||
|  | @ -355,6 +368,8 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | |||
| 
 | ||||
| OwnPtr<FileHandle> VirtualFileSystem::create(const String& path) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     // FIXME: Do the real thing, not just this fake thing!
 | ||||
|     (void) path; | ||||
|     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) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     // FIXME: Do the real thing, not just this fake thing!
 | ||||
|     (void) path; | ||||
|     m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755); | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include <AK/RetainPtr.h> | ||||
| #include <AK/String.h> | ||||
| #include <AK/Vector.h> | ||||
| #include <AK/Lock.h> | ||||
| #include "InodeIdentifier.h" | ||||
| #include "Limits.h" | ||||
| 
 | ||||
|  | @ -15,6 +16,7 @@ class FileSystem; | |||
| class VirtualFileSystem { | ||||
| public: | ||||
|     static void initializeGlobals(); | ||||
|     static SpinLock& lock(); | ||||
| 
 | ||||
|     struct Node { | ||||
|         InodeIdentifier inode; | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ int main(int c, char** v) | |||
|     if (c >= 2) | ||||
|         filename = v[1]; | ||||
| 
 | ||||
|     VirtualFileSystem::initializeGlobals(); | ||||
| 
 | ||||
|     VirtualFileSystem vfs; | ||||
| 
 | ||||
|     auto zero = make<ZeroDevice>(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling