mirror of
https://github.com/RGBCube/serenity
synced 2025-07-02 19:52:07 +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,22 +33,15 @@ 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.
|
vga_set_cursor(0);
|
||||||
for (i = (80 * 24); i < (80 * 25); ++i) {
|
|
||||||
vga_mem[i*2] = ' ';
|
|
||||||
vga_mem[i*2 + 1] = 0x17;
|
|
||||||
}
|
|
||||||
vga_set_cursor( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WORD vga_get_cursor()
|
WORD vga_get_cursor()
|
||||||
|
|
|
@ -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