[Zion] Add a semaphore primitive with related syscalls.

This commit is contained in:
Drew Galbraith 2023-11-22 10:19:56 -08:00
parent 2df1f6c006
commit da3901e104
9 changed files with 107 additions and 1 deletions

View File

@ -31,6 +31,7 @@ add_executable(zion
object/port.cpp object/port.cpp
object/process.cpp object/process.cpp
object/reply_port.cpp object/reply_port.cpp
object/semaphore.cpp
object/thread.cpp object/thread.cpp
scheduler/context_switch.s scheduler/context_switch.s
scheduler/jump_user_space.s scheduler/jump_user_space.s

View File

@ -64,5 +64,8 @@ SYS1(CapRelease, z_cap_t, cap);
SYS1(MutexCreate, z_cap_t*, mutex_cap); SYS1(MutexCreate, z_cap_t*, mutex_cap);
SYS1(MutexLock, z_cap_t, mutex_cap); SYS1(MutexLock, z_cap_t, mutex_cap);
SYS1(MutexRelease, z_cap_t, mutex_cap); SYS1(MutexRelease, z_cap_t, mutex_cap);
SYS1(SemaphoreCreate, z_cap_t*, semaphore_cap);
SYS1(SemaphoreWait, z_cap_t, semaphore_cap);
SYS1(SemaphoreSignal, z_cap_t, semaphore_cap);
SYS1(Debug, const char*, message); SYS1(Debug, const char*, message);

View File

@ -60,6 +60,9 @@ const uint64_t kZionCapRelease = 0x71;
const uint64_t kZionMutexCreate = 0x80; const uint64_t kZionMutexCreate = 0x80;
const uint64_t kZionMutexLock = 0x81; const uint64_t kZionMutexLock = 0x81;
const uint64_t kZionMutexRelease = 0x82; const uint64_t kZionMutexRelease = 0x82;
const uint64_t kZionSemaphoreCreate = 0x83;
const uint64_t kZionSemaphoreWait = 0x84;
const uint64_t kZionSemaphoreSignal = 0x85;
// Debugging Calls. // Debugging Calls.
const uint64_t kZionDebug = 0x1'0000; const uint64_t kZionDebug = 0x1'0000;
@ -89,6 +92,9 @@ const uint64_t kZionPerm_SpawnThread = 0x200;
// Permissions on mutexes. // Permissions on mutexes.
const uint64_t kZionPerm_Lock = 0x100; const uint64_t kZionPerm_Lock = 0x100;
const uint64_t kZionPerm_Release = 0x200; const uint64_t kZionPerm_Release = 0x200;
// Permissions on semaphores.
const uint64_t kZionPerm_Wait = 0x100;
const uint64_t kZionPerm_Signal = 0x200;
const z_perm_t kZionPerm_None = 0; const z_perm_t kZionPerm_None = 0;
const z_perm_t kZionPerm_All = -1; const z_perm_t kZionPerm_All = -1;

View File

@ -15,6 +15,7 @@ class KernelObject : public glcr::RefCounted<KernelObject> {
ENDPOINT = 0x7, ENDPOINT = 0x7,
REPLY_PORT = 0x8, REPLY_PORT = 0x8,
MUTEX = 0x9, MUTEX = 0x9,
SEMAPHORE = 0x10,
}; };
virtual uint64_t TypeTag() = 0; virtual uint64_t TypeTag() = 0;

29
zion/object/semaphore.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "object/semaphore.h"
#include "scheduler/scheduler.h"
glcr::RefPtr<Semaphore> Semaphore::Create() {
return glcr::AdoptPtr<Semaphore>(new Semaphore());
}
// FIXME: We almost certainly have some race conditions
// between this and unlock where we could end up with
// a thread in the blocked_threads_ queue while noone is holding the lock.
void Semaphore::Signal() {
__atomic_fetch_add(&lock_, 0x1, __ATOMIC_SEQ_CST);
if (blocked_threads_.size() > 0) {
auto thread = blocked_threads_.PopFront();
thread->SetState(Thread::RUNNABLE);
gScheduler->Enqueue(thread);
}
}
void Semaphore::Wait() {
while (lock_ == 0) {
auto thread = gScheduler->CurrentThread();
thread->SetState(Thread::BLOCKED);
blocked_threads_.PushBack(thread);
gScheduler->Yield();
}
__atomic_fetch_sub(&lock_, 0x1, __ATOMIC_SEQ_CST);
}

33
zion/object/semaphore.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <glacier/container/intrusive_list.h>
#include <glacier/memory/ref_ptr.h>
#include "include/ztypes.h"
#include "object/kernel_object.h"
#include "object/thread.h"
class Semaphore;
template <>
struct KernelObjectTag<Semaphore> {
static const uint64_t type = KernelObject::SEMAPHORE;
};
class Semaphore : public KernelObject {
public:
uint64_t TypeTag() override { return KernelObject::SEMAPHORE; }
static uint64_t DefaultPermissions() {
return kZionPerm_Wait | kZionPerm_Signal;
}
static glcr::RefPtr<Semaphore> Create();
void Wait();
void Signal();
private:
uint8_t lock_ = 0;
glcr::IntrusiveList<Thread> blocked_threads_;
};

View File

@ -1,6 +1,7 @@
#include "syscall/synchronization.h" #include "syscall/synchronization.h"
#include "object/mutex.h" #include "object/mutex.h"
#include "object/semaphore.h"
#include "scheduler/scheduler.h" #include "scheduler/scheduler.h"
glcr::ErrorCode MutexCreate(ZMutexCreateReq* req) { glcr::ErrorCode MutexCreate(ZMutexCreateReq* req) {
@ -22,10 +23,35 @@ glcr::ErrorCode MutexLock(ZMutexLockReq* req) {
glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req) { glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req) {
auto& curr_proc = gScheduler->CurrentProcess(); auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->mutex_cap); auto cap = curr_proc.GetCapability(req->mutex_cap);
// TODO: We may not want a separate permission for releasing the mutex.
RET_ERR(ValidateCapability<Mutex>(cap, kZionPerm_Release)); RET_ERR(ValidateCapability<Mutex>(cap, kZionPerm_Release));
auto mutex = cap->obj<Mutex>(); auto mutex = cap->obj<Mutex>();
mutex->Release(); mutex->Release();
return glcr::OK; return glcr::OK;
} }
glcr::ErrorCode SemaphoreCreate(ZSemaphoreCreateReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
*req->semaphore_cap = curr_proc.AddNewCapability(Semaphore::Create());
return glcr::OK;
}
glcr::ErrorCode SemaphoreWait(ZSemaphoreWaitReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->semaphore_cap);
RET_ERR(ValidateCapability<Semaphore>(cap, kZionPerm_Wait));
auto semaphore = cap->obj<Semaphore>();
semaphore->Wait();
return glcr::OK;
}
glcr::ErrorCode SemaphoreSignal(ZSemaphoreSignalReq* req) {
auto& curr_proc = gScheduler->CurrentProcess();
auto cap = curr_proc.GetCapability(req->semaphore_cap);
RET_ERR(ValidateCapability<Semaphore>(cap, kZionPerm_Signal));
auto semaphore = cap->obj<Semaphore>();
semaphore->Signal();
return glcr::OK;
}

View File

@ -7,3 +7,7 @@
glcr::ErrorCode MutexCreate(ZMutexCreateReq* req); glcr::ErrorCode MutexCreate(ZMutexCreateReq* req);
glcr::ErrorCode MutexLock(ZMutexLockReq* req); glcr::ErrorCode MutexLock(ZMutexLockReq* req);
glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req); glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req);
glcr::ErrorCode SemaphoreCreate(ZSemaphoreCreateReq* req);
glcr::ErrorCode SemaphoreWait(ZSemaphoreWaitReq* req);
glcr::ErrorCode SemaphoreSignal(ZSemaphoreSignalReq* req);

View File

@ -88,6 +88,9 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
CASE(MutexCreate); CASE(MutexCreate);
CASE(MutexLock); CASE(MutexLock);
CASE(MutexRelease); CASE(MutexRelease);
CASE(SemaphoreCreate);
CASE(SemaphoreWait);
CASE(SemaphoreSignal);
// syscall/debug.h // syscall/debug.h
CASE(Debug); CASE(Debug);
default: default: