From 3aa9f72a8b84eb9e8149e0edfb744c9acea303ad Mon Sep 17 00:00:00 2001 From: Carson Fleming Date: Fri, 20 Feb 2026 00:15:28 -0500 Subject: threads libary --- threads.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 threads.c (limited to 'threads.c') diff --git a/threads.c b/threads.c new file mode 100644 index 0000000..383c8ab --- /dev/null +++ b/threads.c @@ -0,0 +1,142 @@ +#include "threads.h" +#include +#include +#define sema_err (thrd_success - 1) +#define NSEC_PER_SEC ((time_t)1000000000L) + +int sema_init(sema_t* sema, ssize_t value) { + int rv; + + rv = mtx_init(&sema->__lock, mtx_plain); + if (rv != thrd_success) return rv; + + rv = cnd_init(&sema->__cond); + if (rv != thrd_success) { + mtx_destroy(&sema->__lock); + return rv; + } + + sema->__val = value; + return thrd_success; +} + +int sema_get_value(sema_t* sema, ssize_t* p_value) { + int rv; + + rv = mtx_lock(&sema->__lock); + if (rv != thrd_success) return rv; + + *p_value = sema->__val; + + return mtx_unlock(&sema->__lock); +} + +int sema_up(sema_t* sema) { + return sema_up_many(sema, 1); +} + +int sema_up_many(sema_t* sema, ssize_t n) { + int rv; + + rv = mtx_lock(&sema->__lock); + if (rv != thrd_success) return rv; + + sema->__val += n; + + rv = mtx_unlock(&sema->__lock); + if (rv != thrd_success) return rv; + + for (ssize_t i = 0; i < n; i++) { + rv = cnd_signal(&sema->__cond); + if (rv != thrd_success) return rv; + } + return thrd_success; +} + +int sema_down(sema_t* sema) { + return sema_down_many(sema, 1); +} + +int sema_down_many(sema_t* sema, ssize_t n) { + int rv; + + rv = mtx_lock(&sema->__lock); + if (rv != thrd_success) return rv; + + while (sema->__val < n) { + rv = cnd_wait(&sema->__cond, &sema->__lock); + if (rv != thrd_success) return rv; + } + + sema->__val -= n; + return mtx_unlock(&sema->__lock); +} + +int sema_try_down(sema_t* sema) { + return sema_try_down_many(sema, 1); +} + +int sema_try_down_many(sema_t* sema, ssize_t n) { + int rv; + + rv = mtx_lock(&sema->__lock); + if (rv != thrd_success) return rv; + + if (sema->__val < n) { + rv = mtx_unlock(&sema->__lock); + if (rv != thrd_success) return rv; + errno = EAGAIN; + return sema_err; + } + + sema->__val -= n; + return mtx_unlock(&sema->__lock); +} + +int sema_down_timed(sema_t* sema, const struct timespec* time) { + return sema_down_many_timed(sema, time, 1); +} + +static bool diff_timespec( + struct timespec* dst, + const struct timespec* src +) { + *dst = (struct timespec) { + .tv_sec = dst->tv_sec - src->tv_sec, + .tv_nsec = dst->tv_nsec - src->tv_nsec + }; + if (dst->tv_nsec < 0) { + dst->tv_sec--; + dst->tv_nsec += NSEC_PER_SEC; + } + return dst->tv_sec > 0 || (dst->tv_sec == 0 && dst->tv_nsec > 0); +} + +int sema_down_many_timed(sema_t* sema, const struct timespec* time, ssize_t n) { + int rv; + struct timespec start, end, remaining = *time; + + timespec_get(&start, TIME_UTC); + rv = mtx_timedlock(&sema->__lock, &remaining); + if (rv != thrd_success) return rv; + timespec_get(&end, TIME_UTC); + diff_timespec(&end, &start); + if (!diff_timespec(&remaining, &end)) return thrd_timedout; + + while (sema->__val < n) { + timespec_get(&start, TIME_UTC); + rv = cnd_timedwait(&sema->__cond, &sema->__lock, &remaining); + if (rv != thrd_success) return rv; + timespec_get(&end, TIME_UTC); + diff_timespec(&end, &start); + if (!diff_timespec(&remaining, &end)) return thrd_timedout; + } + + sema->__val -= n; + return mtx_unlock(&sema->__lock); +} + +void sema_destroy(sema_t* sema) { + cnd_destroy(&sema->__cond); + mtx_destroy(&sema->__lock); +} -- cgit v1.2.3