[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/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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 "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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue