lib: Add semaphores
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
@@ -23,6 +23,7 @@ kernel_sources += files(
|
||||
'ringbuf.c',
|
||||
'runtime.c',
|
||||
'rwlock.c',
|
||||
'semaphore.c',
|
||||
'spin.c',
|
||||
'stdlib.c',
|
||||
'string.c',
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#include <zinnia/atomic.h>
|
||||
#include <zinnia/park.h>
|
||||
#include <zinnia/semaphore.h>
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user