| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <emscripten/threading.h> |
|
|
| #include "emscripten_internal.h" |
|
|
| void emscripten_lock_init(emscripten_lock_t *lock) { |
| emscripten_atomic_store_u32((void*)lock, EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER); |
| } |
|
|
| bool emscripten_lock_wait_acquire(emscripten_lock_t *lock, int64_t maxWaitNanoseconds) { |
| emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| if (!val) return true; |
| int64_t waitEnd = (int64_t)(emscripten_performance_now() * 1e6) + maxWaitNanoseconds; |
| while (maxWaitNanoseconds > 0) { |
| emscripten_atomic_wait_u32((void*)lock, val, maxWaitNanoseconds); |
| val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| if (!val) return true; |
| maxWaitNanoseconds = waitEnd - (int64_t)(emscripten_performance_now() * 1e6); |
| } |
| return false; |
| } |
|
|
| void emscripten_lock_waitinf_acquire(emscripten_lock_t *lock) { |
| emscripten_lock_t val; |
| do { |
| val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| if (val) { |
| emscripten_atomic_wait_u32((void*)lock, val, ATOMICS_WAIT_DURATION_INFINITE); |
| } |
| } while (val); |
| } |
|
|
| bool emscripten_lock_busyspin_wait_acquire(emscripten_lock_t *lock, double maxWaitMilliseconds) { |
| |
| |
| emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| if (!val) return true; |
|
|
| double t = emscripten_get_now(); |
| double waitEnd = t + maxWaitMilliseconds; |
| while (t < waitEnd) { |
| val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| if (!val) return true; |
| t = emscripten_get_now(); |
| } |
| return false; |
| } |
|
|
| void emscripten_lock_busyspin_waitinf_acquire(emscripten_lock_t *lock) { |
| emscripten_lock_t val; |
| do { |
| val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| } while (val); |
| } |
|
|
| bool emscripten_lock_try_acquire(emscripten_lock_t *lock) { |
| emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1); |
| return !val; |
| } |
|
|
| void emscripten_lock_release(emscripten_lock_t *lock) { |
| emscripten_atomic_store_u32((void*)lock, 0); |
| emscripten_atomic_notify((void*)lock, 1); |
| } |
|
|
| void emscripten_semaphore_init(emscripten_semaphore_t *sem, int num) { |
| emscripten_atomic_store_u32((void*)sem, num); |
| } |
|
|
| int emscripten_semaphore_try_acquire(emscripten_semaphore_t *sem, int num) { |
| uint32_t val = num; |
| for (;;) { |
| uint32_t ret = emscripten_atomic_cas_u32((void*)sem, val, val - num); |
| if (ret == val) return val - num; |
| if (ret < num) return -1; |
| val = ret; |
| } |
| } |
|
|
| int emscripten_semaphore_wait_acquire(emscripten_semaphore_t *sem, int num, int64_t maxWaitNanoseconds) { |
| int val = emscripten_atomic_load_u32((void*)sem); |
| int64_t waitEnd = 0; |
| for (;;) { |
| while (val < num && maxWaitNanoseconds > 0) { |
| |
| |
| if (!waitEnd) waitEnd = (int64_t)(emscripten_performance_now() * 1e6) + maxWaitNanoseconds; |
| emscripten_atomic_wait_u32((void*)sem, val, maxWaitNanoseconds); |
| val = emscripten_atomic_load_u32((void*)sem); |
| maxWaitNanoseconds = waitEnd - (int64_t)(emscripten_performance_now() * 1e6); |
| } |
| |
| if (val < num) return -1; |
| int ret = (int)emscripten_atomic_cas_u32((void*)sem, val, val - num); |
| if (ret == val) return val - num; |
| val = ret; |
| } |
| } |
|
|
| int emscripten_semaphore_waitinf_acquire(emscripten_semaphore_t *sem, int num) { |
| int val = emscripten_atomic_load_u32((void*)sem); |
| for (;;) { |
| while (val < num) { |
| emscripten_atomic_wait_u32((void*)sem, val, ATOMICS_WAIT_DURATION_INFINITE); |
| val = emscripten_atomic_load_u32((void*)sem); |
| } |
| int ret = (int)emscripten_atomic_cas_u32((void*)sem, val, val - num); |
| if (ret == val) return val - num; |
| val = ret; |
| } |
| } |
|
|
| uint32_t emscripten_semaphore_release(emscripten_semaphore_t *sem, int num) { |
| uint32_t ret = emscripten_atomic_add_u32((void*)sem, num); |
| emscripten_atomic_notify((void*)sem, num); |
| return ret; |
| } |
|
|
| void emscripten_condvar_init(emscripten_condvar_t *condvar) { |
| *condvar = EMSCRIPTEN_CONDVAR_T_STATIC_INITIALIZER; |
| } |
|
|
| void emscripten_condvar_waitinf(emscripten_condvar_t *condvar, emscripten_lock_t *lock) { |
| int val = emscripten_atomic_load_u32((void*)condvar); |
| emscripten_lock_release(lock); |
| emscripten_atomic_wait_u32((void*)condvar, val, ATOMICS_WAIT_DURATION_INFINITE); |
| emscripten_lock_waitinf_acquire(lock); |
| } |
|
|
| bool emscripten_condvar_wait(emscripten_condvar_t* condvar, |
| emscripten_lock_t* lock, |
| int64_t maxWaitNanoseconds) { |
| int val = emscripten_atomic_load_u32((void*)condvar); |
| emscripten_lock_release(lock); |
| int waitValue = emscripten_atomic_wait_u32((void*)condvar, val, maxWaitNanoseconds); |
| if (waitValue == ATOMICS_WAIT_TIMED_OUT) { |
| return false; |
| } |
|
|
| return emscripten_lock_wait_acquire(lock, maxWaitNanoseconds); |
| } |
|
|
| ATOMICS_WAIT_TOKEN_T emscripten_condvar_wait_async(emscripten_condvar_t *condvar, |
| emscripten_lock_t *lock, |
| emscripten_async_wait_callback_t asyncWaitFinished, |
| void *userData, |
| double maxWaitMilliseconds) { |
| int val = emscripten_atomic_load_u32((void*)condvar); |
| emscripten_lock_release(lock); |
| return emscripten_atomic_wait_async((void*)condvar, val, asyncWaitFinished, userData, maxWaitMilliseconds); |
| } |
|
|
| void emscripten_condvar_signal(emscripten_condvar_t *condvar, uint32_t numWaitersToSignal) { |
| emscripten_atomic_add_u32((void*)condvar, 1); |
| emscripten_atomic_notify((void*)condvar, numWaitersToSignal); |
| } |
|
|