diff --git a/userspace/libraries/LibC/include/semaphore.h b/userspace/libraries/LibC/include/semaphore.h index 15c343f4..d1dee2e4 100644 --- a/userspace/libraries/LibC/include/semaphore.h +++ b/userspace/libraries/LibC/include/semaphore.h @@ -10,7 +10,11 @@ __BEGIN_DECLS #include #include -typedef void* sem_t; +typedef struct +{ + int shared; + uint32_t value; +} sem_t; #define SEM_FAILED ((sem_t*)0) diff --git a/userspace/libraries/LibC/semaphore.cpp b/userspace/libraries/LibC/semaphore.cpp index dc8b845f..1f53714d 100644 --- a/userspace/libraries/LibC/semaphore.cpp +++ b/userspace/libraries/LibC/semaphore.cpp @@ -1,47 +1,52 @@ -#include +#include #include #include +#include int sem_destroy(sem_t* sem) { (void)sem; - dwarnln("TODO: sem_destroy"); - errno = ENOTSUP; - return -1; + return 0; } int sem_init(sem_t* sem, int pshared, unsigned value) { - (void)sem; - (void)pshared; - (void)value; - dwarnln("TODO: sem_init"); - errno = ENOTSUP; - return -1; + *sem = { + .shared = pshared, + .value = value, + }; + return 0; } int sem_post(sem_t* sem) { - (void)sem; - dwarnln("TODO: sem_post"); - errno = ENOTSUP; - return -1; - + const auto old = BAN::atomic_fetch_add(sem->value, 1); + if (old == 0) + futex(FUTEX_WAKE, &sem->value, 1, nullptr); + return 0; } int sem_trywait(sem_t* sem) { - (void)sem; - dwarnln("TODO: sem_trywait"); - errno = ENOTSUP; + uint32_t expected = BAN::atomic_load(sem->value); + while (expected) + if (BAN::atomic_compare_exchange(sem->value, expected, expected - 1)) + return 0; + errno = EAGAIN; return -1; } int sem_wait(sem_t* sem) { - (void)sem; - dwarnln("TODO: sem_wait"); - errno = ENOTSUP; - return -1; + for (;;) + { + uint32_t expected = BAN::atomic_load(sem->value); + if (expected > 0 && BAN::atomic_compare_exchange(sem->value, expected, expected - 1)) + return 0; + + const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE); + if (futex(op, &sem->value, expected, nullptr) == -1 && errno == EINTR) + return -1; + } }