[Zion] Add a semaphore primitive with related syscalls.
This commit is contained in:
parent
2df1f6c006
commit
da3901e104
|
@ -31,6 +31,7 @@ add_executable(zion
|
|||
object/port.cpp
|
||||
object/process.cpp
|
||||
object/reply_port.cpp
|
||||
object/semaphore.cpp
|
||||
object/thread.cpp
|
||||
scheduler/context_switch.s
|
||||
scheduler/jump_user_space.s
|
||||
|
|
|
@ -64,5 +64,8 @@ SYS1(CapRelease, z_cap_t, cap);
|
|||
SYS1(MutexCreate, z_cap_t*, mutex_cap);
|
||||
SYS1(MutexLock, 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);
|
||||
|
|
|
@ -60,6 +60,9 @@ const uint64_t kZionCapRelease = 0x71;
|
|||
const uint64_t kZionMutexCreate = 0x80;
|
||||
const uint64_t kZionMutexLock = 0x81;
|
||||
const uint64_t kZionMutexRelease = 0x82;
|
||||
const uint64_t kZionSemaphoreCreate = 0x83;
|
||||
const uint64_t kZionSemaphoreWait = 0x84;
|
||||
const uint64_t kZionSemaphoreSignal = 0x85;
|
||||
|
||||
// Debugging Calls.
|
||||
const uint64_t kZionDebug = 0x1'0000;
|
||||
|
@ -89,6 +92,9 @@ const uint64_t kZionPerm_SpawnThread = 0x200;
|
|||
// Permissions on mutexes.
|
||||
const uint64_t kZionPerm_Lock = 0x100;
|
||||
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_All = -1;
|
||||
|
|
|
@ -15,6 +15,7 @@ class KernelObject : public glcr::RefCounted<KernelObject> {
|
|||
ENDPOINT = 0x7,
|
||||
REPLY_PORT = 0x8,
|
||||
MUTEX = 0x9,
|
||||
SEMAPHORE = 0x10,
|
||||
};
|
||||
|
||||
virtual uint64_t TypeTag() = 0;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_;
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
#include "syscall/synchronization.h"
|
||||
|
||||
#include "object/mutex.h"
|
||||
#include "object/semaphore.h"
|
||||
#include "scheduler/scheduler.h"
|
||||
|
||||
glcr::ErrorCode MutexCreate(ZMutexCreateReq* req) {
|
||||
|
@ -22,10 +23,35 @@ glcr::ErrorCode MutexLock(ZMutexLockReq* req) {
|
|||
glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req) {
|
||||
auto& curr_proc = gScheduler->CurrentProcess();
|
||||
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));
|
||||
|
||||
auto mutex = cap->obj<Mutex>();
|
||||
mutex->Release();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -7,3 +7,7 @@
|
|||
glcr::ErrorCode MutexCreate(ZMutexCreateReq* req);
|
||||
glcr::ErrorCode MutexLock(ZMutexLockReq* req);
|
||||
glcr::ErrorCode MutexRelease(ZMutexReleaseReq* req);
|
||||
|
||||
glcr::ErrorCode SemaphoreCreate(ZSemaphoreCreateReq* req);
|
||||
glcr::ErrorCode SemaphoreWait(ZSemaphoreWaitReq* req);
|
||||
glcr::ErrorCode SemaphoreSignal(ZSemaphoreSignalReq* req);
|
||||
|
|
|
@ -88,6 +88,9 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
|
|||
CASE(MutexCreate);
|
||||
CASE(MutexLock);
|
||||
CASE(MutexRelease);
|
||||
CASE(SemaphoreCreate);
|
||||
CASE(SemaphoreWait);
|
||||
CASE(SemaphoreSignal);
|
||||
// syscall/debug.h
|
||||
CASE(Debug);
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue