Path: blob/main/system/lib/pthread/emscripten_thread_primitives.c
7086 views
/*1* Copyright 2026 The Emscripten Authors. All rights reserved.2* Emscripten is available under two separate licenses, the MIT license and the3* University of Illinois/NCSA Open Source License. Both these licenses can be4* found in the LICENSE file.5*6* Low level threading primitives for lock, condvar and mutex, build on the7* emscripten atomics API.8*/9#include <emscripten/threading.h>1011#include "emscripten_internal.h"1213void emscripten_lock_init(emscripten_lock_t *lock) {14emscripten_atomic_store_u32((void*)lock, EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER);15}1617bool emscripten_lock_wait_acquire(emscripten_lock_t *lock, int64_t maxWaitNanoseconds) {18emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);19if (!val) return true;20int64_t waitEnd = (int64_t)(emscripten_performance_now() * 1e6) + maxWaitNanoseconds;21while (maxWaitNanoseconds > 0) {22emscripten_atomic_wait_u32((void*)lock, val, maxWaitNanoseconds);23val = emscripten_atomic_cas_u32((void*)lock, 0, 1);24if (!val) return true;25maxWaitNanoseconds = waitEnd - (int64_t)(emscripten_performance_now() * 1e6);26}27return false;28}2930void emscripten_lock_waitinf_acquire(emscripten_lock_t *lock) {31emscripten_lock_t val;32do {33val = emscripten_atomic_cas_u32((void*)lock, 0, 1);34if (val) {35emscripten_atomic_wait_u32((void*)lock, val, ATOMICS_WAIT_DURATION_INFINITE);36}37} while (val);38}3940bool emscripten_lock_busyspin_wait_acquire(emscripten_lock_t *lock, double maxWaitMilliseconds) {41// TODO: we changed the performance_now calls to get_now, which can be applied42// to the remaining code (since all calls defer to the best internal option).43emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);44if (!val) return true;4546double t = emscripten_get_now();47double waitEnd = t + maxWaitMilliseconds;48while (t < waitEnd) {49val = emscripten_atomic_cas_u32((void*)lock, 0, 1);50if (!val) return true;51t = emscripten_get_now();52}53return false;54}5556void emscripten_lock_busyspin_waitinf_acquire(emscripten_lock_t *lock) {57emscripten_lock_t val;58do {59val = emscripten_atomic_cas_u32((void*)lock, 0, 1);60} while (val);61}6263bool emscripten_lock_try_acquire(emscripten_lock_t *lock) {64emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);65return !val;66}6768void emscripten_lock_release(emscripten_lock_t *lock) {69emscripten_atomic_store_u32((void*)lock, 0);70emscripten_atomic_notify((void*)lock, 1);71}7273void emscripten_semaphore_init(emscripten_semaphore_t *sem, int num) {74emscripten_atomic_store_u32((void*)sem, num);75}7677int emscripten_semaphore_try_acquire(emscripten_semaphore_t *sem, int num) {78uint32_t val = num;79for (;;) {80uint32_t ret = emscripten_atomic_cas_u32((void*)sem, val, val - num);81if (ret == val) return val - num;82if (ret < num) return -1;83val = ret;84}85}8687int emscripten_semaphore_wait_acquire(emscripten_semaphore_t *sem, int num, int64_t maxWaitNanoseconds) {88int val = emscripten_atomic_load_u32((void*)sem);89int64_t waitEnd = 0;90for (;;) {91while (val < num && maxWaitNanoseconds > 0) {92// Deley initialization of waitEnd until we know we are going to need to93// wait (since emscripten_performance_now is not cheap).94if (!waitEnd) waitEnd = (int64_t)(emscripten_performance_now() * 1e6) + maxWaitNanoseconds;95emscripten_atomic_wait_u32((void*)sem, val, maxWaitNanoseconds);96val = emscripten_atomic_load_u32((void*)sem);97maxWaitNanoseconds = waitEnd - (int64_t)(emscripten_performance_now() * 1e6);98}99// If we exited the loop and still don't have enough, it means we timed out.100if (val < num) return -1;101int ret = (int)emscripten_atomic_cas_u32((void*)sem, val, val - num);102if (ret == val) return val - num;103val = ret;104}105}106107int emscripten_semaphore_waitinf_acquire(emscripten_semaphore_t *sem, int num) {108int val = emscripten_atomic_load_u32((void*)sem);109for (;;) {110while (val < num) {111emscripten_atomic_wait_u32((void*)sem, val, ATOMICS_WAIT_DURATION_INFINITE);112val = emscripten_atomic_load_u32((void*)sem);113}114int ret = (int)emscripten_atomic_cas_u32((void*)sem, val, val - num);115if (ret == val) return val - num;116val = ret;117}118}119120uint32_t emscripten_semaphore_release(emscripten_semaphore_t *sem, int num) {121uint32_t ret = emscripten_atomic_add_u32((void*)sem, num);122emscripten_atomic_notify((void*)sem, num);123return ret;124}125126void emscripten_condvar_init(emscripten_condvar_t *condvar) {127*condvar = EMSCRIPTEN_CONDVAR_T_STATIC_INITIALIZER;128}129130void emscripten_condvar_waitinf(emscripten_condvar_t *condvar, emscripten_lock_t *lock) {131int val = emscripten_atomic_load_u32((void*)condvar);132emscripten_lock_release(lock);133emscripten_atomic_wait_u32((void*)condvar, val, ATOMICS_WAIT_DURATION_INFINITE);134emscripten_lock_waitinf_acquire(lock);135}136137bool emscripten_condvar_wait(emscripten_condvar_t* condvar,138emscripten_lock_t* lock,139int64_t maxWaitNanoseconds) {140int val = emscripten_atomic_load_u32((void*)condvar);141emscripten_lock_release(lock);142int waitValue = emscripten_atomic_wait_u32((void*)condvar, val, maxWaitNanoseconds);143if (waitValue == ATOMICS_WAIT_TIMED_OUT) {144return false;145}146147return emscripten_lock_wait_acquire(lock, maxWaitNanoseconds);148}149150ATOMICS_WAIT_TOKEN_T emscripten_condvar_wait_async(emscripten_condvar_t *condvar,151emscripten_lock_t *lock,152emscripten_async_wait_callback_t asyncWaitFinished,153void *userData,154double maxWaitMilliseconds) {155int val = emscripten_atomic_load_u32((void*)condvar);156emscripten_lock_release(lock);157return emscripten_atomic_wait_async((void*)condvar, val, asyncWaitFinished, userData, maxWaitMilliseconds);158}159160void emscripten_condvar_signal(emscripten_condvar_t *condvar, uint32_t numWaitersToSignal) {161emscripten_atomic_add_u32((void*)condvar, 1);162emscripten_atomic_notify((void*)condvar, numWaitersToSignal);163}164165166