Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/pthread/emscripten_thread_primitives.c
7086 views
1
/*
2
* Copyright 2026 The Emscripten Authors. All rights reserved.
3
* Emscripten is available under two separate licenses, the MIT license and the
4
* University of Illinois/NCSA Open Source License. Both these licenses can be
5
* found in the LICENSE file.
6
*
7
* Low level threading primitives for lock, condvar and mutex, build on the
8
* emscripten atomics API.
9
*/
10
#include <emscripten/threading.h>
11
12
#include "emscripten_internal.h"
13
14
void emscripten_lock_init(emscripten_lock_t *lock) {
15
emscripten_atomic_store_u32((void*)lock, EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER);
16
}
17
18
bool emscripten_lock_wait_acquire(emscripten_lock_t *lock, int64_t maxWaitNanoseconds) {
19
emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
20
if (!val) return true;
21
int64_t waitEnd = (int64_t)(emscripten_performance_now() * 1e6) + maxWaitNanoseconds;
22
while (maxWaitNanoseconds > 0) {
23
emscripten_atomic_wait_u32((void*)lock, val, maxWaitNanoseconds);
24
val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
25
if (!val) return true;
26
maxWaitNanoseconds = waitEnd - (int64_t)(emscripten_performance_now() * 1e6);
27
}
28
return false;
29
}
30
31
void emscripten_lock_waitinf_acquire(emscripten_lock_t *lock) {
32
emscripten_lock_t val;
33
do {
34
val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
35
if (val) {
36
emscripten_atomic_wait_u32((void*)lock, val, ATOMICS_WAIT_DURATION_INFINITE);
37
}
38
} while (val);
39
}
40
41
bool emscripten_lock_busyspin_wait_acquire(emscripten_lock_t *lock, double maxWaitMilliseconds) {
42
// TODO: we changed the performance_now calls to get_now, which can be applied
43
// to the remaining code (since all calls defer to the best internal option).
44
emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
45
if (!val) return true;
46
47
double t = emscripten_get_now();
48
double waitEnd = t + maxWaitMilliseconds;
49
while (t < waitEnd) {
50
val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
51
if (!val) return true;
52
t = emscripten_get_now();
53
}
54
return false;
55
}
56
57
void emscripten_lock_busyspin_waitinf_acquire(emscripten_lock_t *lock) {
58
emscripten_lock_t val;
59
do {
60
val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
61
} while (val);
62
}
63
64
bool emscripten_lock_try_acquire(emscripten_lock_t *lock) {
65
emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
66
return !val;
67
}
68
69
void emscripten_lock_release(emscripten_lock_t *lock) {
70
emscripten_atomic_store_u32((void*)lock, 0);
71
emscripten_atomic_notify((void*)lock, 1);
72
}
73
74
void emscripten_semaphore_init(emscripten_semaphore_t *sem, int num) {
75
emscripten_atomic_store_u32((void*)sem, num);
76
}
77
78
int emscripten_semaphore_try_acquire(emscripten_semaphore_t *sem, int num) {
79
uint32_t val = num;
80
for (;;) {
81
uint32_t ret = emscripten_atomic_cas_u32((void*)sem, val, val - num);
82
if (ret == val) return val - num;
83
if (ret < num) return -1;
84
val = ret;
85
}
86
}
87
88
int emscripten_semaphore_wait_acquire(emscripten_semaphore_t *sem, int num, int64_t maxWaitNanoseconds) {
89
int val = emscripten_atomic_load_u32((void*)sem);
90
int64_t waitEnd = 0;
91
for (;;) {
92
while (val < num && maxWaitNanoseconds > 0) {
93
// Deley initialization of waitEnd until we know we are going to need to
94
// wait (since emscripten_performance_now is not cheap).
95
if (!waitEnd) waitEnd = (int64_t)(emscripten_performance_now() * 1e6) + maxWaitNanoseconds;
96
emscripten_atomic_wait_u32((void*)sem, val, maxWaitNanoseconds);
97
val = emscripten_atomic_load_u32((void*)sem);
98
maxWaitNanoseconds = waitEnd - (int64_t)(emscripten_performance_now() * 1e6);
99
}
100
// If we exited the loop and still don't have enough, it means we timed out.
101
if (val < num) return -1;
102
int ret = (int)emscripten_atomic_cas_u32((void*)sem, val, val - num);
103
if (ret == val) return val - num;
104
val = ret;
105
}
106
}
107
108
int emscripten_semaphore_waitinf_acquire(emscripten_semaphore_t *sem, int num) {
109
int val = emscripten_atomic_load_u32((void*)sem);
110
for (;;) {
111
while (val < num) {
112
emscripten_atomic_wait_u32((void*)sem, val, ATOMICS_WAIT_DURATION_INFINITE);
113
val = emscripten_atomic_load_u32((void*)sem);
114
}
115
int ret = (int)emscripten_atomic_cas_u32((void*)sem, val, val - num);
116
if (ret == val) return val - num;
117
val = ret;
118
}
119
}
120
121
uint32_t emscripten_semaphore_release(emscripten_semaphore_t *sem, int num) {
122
uint32_t ret = emscripten_atomic_add_u32((void*)sem, num);
123
emscripten_atomic_notify((void*)sem, num);
124
return ret;
125
}
126
127
void emscripten_condvar_init(emscripten_condvar_t *condvar) {
128
*condvar = EMSCRIPTEN_CONDVAR_T_STATIC_INITIALIZER;
129
}
130
131
void emscripten_condvar_waitinf(emscripten_condvar_t *condvar, emscripten_lock_t *lock) {
132
int val = emscripten_atomic_load_u32((void*)condvar);
133
emscripten_lock_release(lock);
134
emscripten_atomic_wait_u32((void*)condvar, val, ATOMICS_WAIT_DURATION_INFINITE);
135
emscripten_lock_waitinf_acquire(lock);
136
}
137
138
bool emscripten_condvar_wait(emscripten_condvar_t* condvar,
139
emscripten_lock_t* lock,
140
int64_t maxWaitNanoseconds) {
141
int val = emscripten_atomic_load_u32((void*)condvar);
142
emscripten_lock_release(lock);
143
int waitValue = emscripten_atomic_wait_u32((void*)condvar, val, maxWaitNanoseconds);
144
if (waitValue == ATOMICS_WAIT_TIMED_OUT) {
145
return false;
146
}
147
148
return emscripten_lock_wait_acquire(lock, maxWaitNanoseconds);
149
}
150
151
ATOMICS_WAIT_TOKEN_T emscripten_condvar_wait_async(emscripten_condvar_t *condvar,
152
emscripten_lock_t *lock,
153
emscripten_async_wait_callback_t asyncWaitFinished,
154
void *userData,
155
double maxWaitMilliseconds) {
156
int val = emscripten_atomic_load_u32((void*)condvar);
157
emscripten_lock_release(lock);
158
return emscripten_atomic_wait_async((void*)condvar, val, asyncWaitFinished, userData, maxWaitMilliseconds);
159
}
160
161
void emscripten_condvar_signal(emscripten_condvar_t *condvar, uint32_t numWaitersToSignal) {
162
emscripten_atomic_add_u32((void*)condvar, 1);
163
emscripten_atomic_notify((void*)condvar, numWaitersToSignal);
164
}
165
166