From 9c5804c84869486dcf49586cb8ff93279c967f1c Mon Sep 17 00:00:00 2001 From: Marvin Friedrich Date: Wed, 28 Oct 2026 21:46:25 +0100 Subject: [PATCH] lib: Add semaphores --- include/zinnia/semaphore.h | 15 ++++++++++++++ lib/meson.build | 1 + lib/semaphore.c | 40 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 include/zinnia/semaphore.h create mode 100644 lib/semaphore.c diff --git a/include/zinnia/semaphore.h b/include/zinnia/semaphore.h new file mode 100644 index 0000000..1cfd4f5 --- /dev/null +++ b/include/zinnia/semaphore.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: ISC + +#pragma once + +#include + +typedef struct { + _Atomic(uint32_t) count; +} sem_t; + +void sem_init(sem_t* sem, uint32_t count); +bool sem_trywait(sem_t* sem); +bool sem_timedwait(sem_t* sem, const uint64_t* deadline_ns); +void sem_wait(sem_t* sem); +void sem_post(sem_t* sem); diff --git a/lib/meson.build b/lib/meson.build index 370118d..f28f2b1 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -23,6 +23,7 @@ kernel_sources += files( 'ringbuf.c', 'runtime.c', 'rwlock.c', + 'semaphore.c', 'spin.c', 'stdlib.c', 'string.c', diff --git a/lib/semaphore.c b/lib/semaphore.c new file mode 100644 index 0000000..78a5efa --- /dev/null +++ b/lib/semaphore.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: ISC + +#include +#include +#include + +void sem_init(sem_t* sem, uint32_t count) { + atomic_store(&sem->count, count, ATOMIC_RELAXED); +} + +bool sem_trywait(sem_t* sem) { + uint32_t count = atomic_load(&sem->count, ATOMIC_RELAXED); + while (count) { + if (atomic_compare_exchange_weak(&sem->count, &count, count - 1, ATOMIC_ACQUIRE, ATOMIC_RELAXED)) + return true; + } + return false; +} + +static bool sem_empty(void* ctx) { + sem_t* sem = ctx; + return atomic_load(&sem->count, ATOMIC_RELAXED) == 0; +} + +bool sem_timedwait(sem_t* sem, const uint64_t* deadline_ns) { + while (!sem_trywait(sem)) { + if (park_timeout(sem, sem_empty, nullptr, sem, 0, deadline_ns).status == PARK_TIMED_OUT) + return sem_trywait(sem); + } + return true; +} + +void sem_wait(sem_t* sem) { + sem_timedwait(sem, nullptr); +} + +void sem_post(sem_t* sem) { + atomic_fetch_add(&sem->count, 1, ATOMIC_RELEASE); + unpark_one(sem, nullptr, nullptr); +}