From 4ac393f866317c66d8fe807102e679ff7c979579 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Sun, 16 Aug 2026 18:20:21 +0100 Subject: [PATCH] [std] Merge semaphore and lock primitives Rather than introducing a new semaphore primitive, we can just add a new primitive to construct a lock with an initial count. --- libs/std/thread.c | 163 +++++----------------------------------------- 1 file changed, 17 insertions(+), 146 deletions(-) diff --git a/libs/std/thread.c b/libs/std/thread.c index 13a2193e..34f0b858 100644 --- a/libs/std/thread.c +++ b/libs/std/thread.c @@ -334,19 +334,22 @@ static void free_lock( value l ) { } /** - lock_create : void -> 'lock - Creates a lock which is initially locked + lock_create : initial_count:int -> 'lock + Creates a lock initialised with a count of [initial_count]. **/ -static value lock_create() { +static value lock_create_with_count( value initial_count ) { value vl; vlock l; + if (!val_is_any_int(initial_count)) { + neko_error(); + } # ifdef NEKO_WINDOWS - l = CreateSemaphore(NULL,0,(1 << 30),NULL); + l = CreateSemaphore(NULL,val_any_int(initial_count),(1 << 30),NULL); if( l == NULL ) neko_error(); # else l = (vlock)alloc_private(sizeof(struct _vlock)); - l->counter = 0; + l->counter = val_any_int(initial_count); if( pthread_mutex_init(&l->lock,NULL) != 0 || pthread_cond_init(&l->cond,NULL) != 0 ) neko_error(); # endif @@ -355,6 +358,14 @@ static value lock_create() { return vl; } +/** + lock_create : void -> 'lock + Creates a lock which is initially locked +**/ +static value lock_create() { + return lock_create_with_count(alloc_int(0)); +} + /** lock_release : 'lock -> void @@ -635,6 +646,7 @@ DEFINE_PRIM(thread_read_message,1); DEFINE_PRIM(thread_stack,1); DEFINE_PRIM(lock_create,0); +DEFINE_PRIM_WITH_NAME(lock_create_with_count, lock_create, 1); DEFINE_PRIM(lock_wait,2); DEFINE_PRIM(lock_release,1); @@ -788,144 +800,3 @@ DEFINE_PRIM(cond_release, 1) DEFINE_PRIM(cond_wait, 1) DEFINE_PRIM(cond_signal, 1) DEFINE_PRIM(cond_broadcast, 1) - -typedef struct { - vcondition c; - int counter; -} vsemaphore; - -DEFINE_KIND(k_semaphore); -#define val_semaphore(s) ((vsemaphore *)val_data(s)) - -static void _semaphore_init(vsemaphore *s, int value) { - _cond_init(&s->c); - s->counter = value; -} -static void _semaphore_acquire(vsemaphore *s) { - _cond_acquire(&s->c); - // wait until s->counter is greater than zero - while(s->counter == 0) { - _cond_wait(&s->c); - } - // s->counter is now greater than zero, decrease it - s->counter--; - _cond_release(&s->c); -} - -#ifdef NEKO_WINDOWS -static long long now_ms() { - static LARGE_INTEGER freq = {0}; - if (freq.QuadPart == 0) { - QueryPerformanceFrequency(&freq); - } - LARGE_INTEGER time; - QueryPerformanceCounter(&time); - return time.QuadPart * 1000LL / freq.QuadPart; -} -#endif - -static bool _semaphore_try_acquire(vsemaphore *s, double *timeout) { - bool success = false; - _cond_acquire(&s->c); - if (timeout) { - #ifdef NEKO_WINDOWS - long long start_ms = now_ms(); - - long timeout_ms = *timeout * 1000; - while (s->counter == 0) { - long long elapsed = now_ms() - start_ms; - long long ms = elapsed - timeout_ms; - if (ms <= 0 || SleepConditionVariableSRW(&s->c.cond, &s->c.lock, ms, 0) == 0) { - break; - } - } - #else - double seconds = *timeout; - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - time_t whole_seconds = seconds; - long nanoseconds = - ((seconds - whole_seconds) * 1e9) + ts.tv_nsec; - whole_seconds += ts.tv_sec; - long sec_in_ns = (long)(nanoseconds / 1e9); - whole_seconds += sec_in_ns; - nanoseconds -= sec_in_ns * 1e9; - ts.tv_sec = whole_seconds; - ts.tv_nsec = nanoseconds; - while (s->counter == 0) { - if (pthread_cond_timedwait(&s->c.cond, &s->c.lock, &ts) == ETIMEDOUT) { - break; - } - } - #endif - if (s->counter > 0) { - s->counter--; - success = true; - } - } else { - if (s->counter > 0) { - s->counter--; - success = true; - } - } - _cond_release(&s->c); - return success; -} - -static void _semaphore_release(vsemaphore *s) { - _cond_acquire(&s->c); - s->counter++; - _cond_signal(&s->c); - _cond_release(&s->c); -} - -static void _semaphore_destroy(vsemaphore *s) { - _cond_destroy(&s->c); -} - -static void free_semaphore(value s) { - _semaphore_destroy(val_semaphore(s)); -} - -static value semaphore_create(value initial_count) { - if (!val_is_any_int(initial_count)) { - neko_error(); - } - vsemaphore *c = (vsemaphore *)alloc(sizeof(vsemaphore)); - value v = alloc_abstract(k_semaphore, c); - val_gc(v, free_semaphore); - _semaphore_init(c, val_any_int(initial_count)); - return v; -} - -static value semaphore_acquire(value s) { - val_check_kind(s, k_semaphore); - _semaphore_acquire(val_semaphore(s)); - return val_null; -} - -static value semaphore_try_acquire(value s, value timeout) { - int has_timeout = !val_is_null(timeout); - val_check_kind(s, k_semaphore); - double time = 0.0; - if (has_timeout) { - val_check(timeout, number); - time = val_number(timeout); - } - if (_semaphore_try_acquire(val_semaphore(s), has_timeout ? &time : NULL)) { - return val_true; - } else { - return val_false; - } -} - -static value semaphore_release(value s) { - val_check_kind(s, k_semaphore); - _semaphore_release(val_semaphore(s)); - return val_null; -} - -DEFINE_PRIM(semaphore_create, 1) -DEFINE_PRIM(semaphore_acquire, 1) -DEFINE_PRIM(semaphore_try_acquire, 2) -DEFINE_PRIM(semaphore_release, 1) \ No newline at end of file