Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/pthread/library_pthread_stub.c
6175 views
1
/*
2
* Copyright 2019 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
8
#include <errno.h>
9
#include <stdbool.h>
10
#include <pthread.h>
11
#include <semaphore.h>
12
#include <stdint.h>
13
#include <stdlib.h>
14
#include <unistd.h>
15
#include "pthread_impl.h"
16
#include <emscripten/stack.h>
17
#include <emscripten/threading.h>
18
#include <emscripten/emscripten.h>
19
20
int emscripten_has_threading_support() { return 0; }
21
22
int emscripten_num_logical_cores() { return 1; }
23
24
int emscripten_futex_wait(
25
volatile void /*uint32_t*/* addr, uint32_t val, double maxWaitMilliseconds) {
26
// nop
27
return 0; // success
28
}
29
30
int emscripten_futex_wake(volatile void /*uint32_t*/* addr, int count) {
31
// nop
32
return 0; // success
33
}
34
35
int emscripten_is_main_runtime_thread() { return 1; }
36
37
void emscripten_main_thread_process_queued_calls() {
38
// nop
39
}
40
41
void emscripten_current_thread_process_queued_calls() {
42
// nop
43
}
44
45
static void dummy(double now)
46
{
47
}
48
49
weak_alias(dummy, _emscripten_check_timers);
50
51
void _emscripten_yield(double now) {
52
_emscripten_check_timers(now);
53
}
54
55
int pthread_mutex_init(
56
pthread_mutex_t* __restrict mutex, const pthread_mutexattr_t* __restrict attr) {
57
return 0;
58
}
59
60
int __pthread_mutex_lock(pthread_mutex_t* mutex) { return 0; }
61
62
weak_alias(__pthread_mutex_lock, pthread_mutex_lock);
63
64
int __pthread_mutex_unlock(pthread_mutex_t* mutex) { return 0; }
65
66
weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
67
68
int __pthread_mutex_trylock(pthread_mutex_t* mutex) { return 0; }
69
70
weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
71
72
struct timespec;
73
74
int __pthread_mutex_timedlock(
75
pthread_mutex_t* __restrict mutex, const struct timespec* __restrict t) {
76
return 0;
77
}
78
79
weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock);
80
81
int pthread_mutex_destroy(pthread_mutex_t* mutex) { return 0; }
82
83
int pthread_mutex_consistent(pthread_mutex_t* mutex) { return 0; }
84
85
int pthread_barrier_init(
86
pthread_barrier_t* __restrict mutex, const pthread_barrierattr_t* __restrict attr, unsigned u) {
87
return 0;
88
}
89
90
int pthread_barrier_destroy(pthread_barrier_t* mutex) { return 0; }
91
92
int pthread_barrier_wait(pthread_barrier_t* mutex) { return 0; }
93
94
int __pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) {
95
// ENOTSUP, while not mentioned in the pthread_create docs, does better
96
// describe the situation.
97
// See https://github.com/WebAssembly/wasi-libc/pull/716 for discussion
98
// on this error code vs, for example, EAGAIN.
99
return ENOTSUP;
100
}
101
102
weak_alias(__pthread_create, emscripten_builtin_pthread_create);
103
weak_alias(__pthread_create, pthread_create);
104
105
int __pthread_join(pthread_t thread, void **retval) {
106
return EINVAL;
107
}
108
109
weak_alias(__pthread_join, emscripten_builtin_pthread_join);
110
weak_alias(__pthread_join, pthread_join);
111
112
static void* tls_entries[PTHREAD_KEYS_MAX];
113
static bool tls_key_used[PTHREAD_KEYS_MAX];
114
115
int __pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) {
116
if (key == 0) {
117
return EINVAL;
118
}
119
// Find empty spot.
120
for (pthread_key_t entry = 0; entry < PTHREAD_KEYS_MAX; entry++) {
121
if (!tls_key_used[entry]) {
122
tls_key_used[entry] = true;
123
tls_entries[entry] = NULL;
124
*key = entry;
125
return 0;
126
}
127
}
128
// No empty spots, return an error
129
return EAGAIN;
130
}
131
132
int __pthread_key_delete(pthread_key_t key) {
133
if (key < 0 || key >= PTHREAD_KEYS_MAX) {
134
return EINVAL;
135
}
136
if (!tls_key_used[key]) {
137
return EINVAL;
138
}
139
tls_key_used[key] = false;
140
tls_entries[key] = NULL;
141
return 0;
142
}
143
144
weak_alias(__pthread_key_delete, pthread_key_delete);
145
weak_alias(__pthread_key_create, pthread_key_create);
146
147
void* pthread_getspecific(pthread_key_t key) {
148
if (key < 0 || key >= PTHREAD_KEYS_MAX) {
149
return NULL;
150
}
151
if (!tls_key_used[key]) {
152
return NULL;
153
}
154
return tls_entries[key];
155
}
156
157
int pthread_setspecific(pthread_key_t key, const void* value) {
158
if (key < 0 || key >= PTHREAD_KEYS_MAX) {
159
return EINVAL;
160
}
161
if (!tls_key_used[key]) {
162
return EINVAL;
163
}
164
tls_entries[key] = (void*)value;
165
return 0;
166
}
167
168
/*magic number to detect if we have not run yet*/
169
#define PTHREAD_ONCE_MAGIC_ID 0x13579BDF
170
171
int __pthread_once(pthread_once_t* once_control, void (*init_routine)(void)) {
172
if (*once_control != PTHREAD_ONCE_MAGIC_ID) {
173
init_routine();
174
*once_control = PTHREAD_ONCE_MAGIC_ID;
175
}
176
return 0;
177
}
178
179
weak_alias(__pthread_once, pthread_once);
180
181
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
182
return 0;
183
}
184
185
int pthread_cond_signal(pthread_cond_t *cond) {
186
return 0;
187
}
188
189
int __private_cond_signal(pthread_cond_t *c, int n) {
190
return 0;
191
}
192
193
int pthread_cond_broadcast(pthread_cond_t *cond) {
194
return 0;
195
}
196
197
int pthread_cond_init(pthread_cond_t *__restrict x, const pthread_condattr_t *__restrict y) {
198
return 0;
199
}
200
201
int pthread_cond_destroy(pthread_cond_t * x) {
202
return 0;
203
}
204
205
int __pthread_cond_timedwait(pthread_cond_t *__restrict x, pthread_mutex_t *__restrict y, const struct timespec *__restrict z) {
206
return 0;
207
}
208
209
weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait);
210
211
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) {
212
return 0;
213
}
214
215
int pthread_cancel(pthread_t thread) {
216
return 0;
217
}
218
219
void pthread_testcancel() {}
220
221
_Noreturn void __pthread_exit(void* status) {
222
exit(0);
223
}
224
225
weak_alias(__pthread_exit, emscripten_builtin_pthread_exit);
226
weak_alias(__pthread_exit, pthread_exit);
227
228
int __pthread_detach(pthread_t t) {
229
return 0;
230
}
231
232
weak_alias(__pthread_detach, emscripten_builtin_pthread_detach);
233
weak_alias(__pthread_detach, pthread_detach);
234
weak_alias(__pthread_detach, thrd_detach);
235
236
// pthread_equal is defined as a macro in C, as a function for C++; undef it
237
// here so we define the function for C++ that links to us.
238
#ifdef pthread_equal
239
#undef pthread_equal
240
#endif
241
242
int pthread_equal(pthread_t t1, pthread_t t2) {
243
return t1 == t2;
244
}
245
246
int pthread_mutexattr_init(pthread_mutexattr_t *attr) {
247
return 0;
248
}
249
250
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) {
251
return 0;
252
}
253
254
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) {
255
return 0;
256
}
257
258
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) {
259
return 0;
260
}
261
262
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) {
263
// XXX implement if/when getpshared is required
264
return 0;
265
}
266
267
int pthread_condattr_init(pthread_condattr_t * attr) {
268
return 0;
269
}
270
271
int pthread_condattr_destroy(pthread_condattr_t *attr) {
272
return 0;
273
}
274
275
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clk) {
276
return 0;
277
}
278
279
int pthread_condattr_setpshared(pthread_condattr_t *attr, int shared) {
280
return 0;
281
}
282
283
int pthread_setcancelstate(int state, int* oldstate) {
284
return 0;
285
}
286
287
int pthread_setcanceltype(int type, int* oldtype) {
288
return 0;
289
}
290
291
int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr) {
292
return 0;
293
}
294
295
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) {
296
return 0;
297
}
298
299
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) {
300
return 0;
301
}
302
303
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) {
304
return 0;
305
}
306
307
int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock, const struct timespec* abs_timeout) {
308
return 0;
309
}
310
311
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) {
312
return 0;
313
}
314
315
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) {
316
return 0;
317
}
318
319
int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock, const struct timespec* abs_timeout) {
320
return 0;
321
}
322
323
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) {
324
return 0;
325
}
326
327
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) {
328
return 0;
329
}
330
331
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) {
332
return 0;
333
}
334
335
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared) {
336
return 0;
337
}
338
339
int pthread_spin_init(pthread_spinlock_t *lock, int pshared) {
340
return 0;
341
}
342
343
int pthread_spin_destroy(pthread_spinlock_t *lock) {
344
return 0;
345
}
346
347
int pthread_spin_lock(pthread_spinlock_t *lock) {
348
return 0;
349
}
350
351
int pthread_spin_trylock(pthread_spinlock_t *lock) {
352
return 0;
353
}
354
355
int pthread_spin_unlock(pthread_spinlock_t *lock) {
356
return 0;
357
}
358
359
int sem_init(sem_t *sem, int pshared, unsigned int value) {
360
return 0;
361
}
362
363
int sem_post(sem_t *sem) {
364
return 0;
365
}
366
367
int sem_wait(sem_t *sem) {
368
return 0;
369
}
370
371
int sem_trywait(sem_t *sem) {
372
return 0;
373
}
374
375
int sem_destroy(sem_t *sem) {
376
return 0;
377
}
378
379
void __wait(volatile int *addr, volatile int *waiters, int val, int priv) {}
380
381
void __lock(void* ptr) {}
382
383
void __unlock(void* ptr) {}
384
385
void __acquire_ptc() {}
386
387
void __release_ptc() {}
388
389
// When pthreads is not enabled, we can't use the Atomics futex api to do
390
// proper sleeps, so simulate a busy spin wait loop instead.
391
void emscripten_thread_sleep(double msecs) {
392
double start = emscripten_get_now();
393
double now = start;
394
do {
395
_emscripten_yield(now);
396
now = emscripten_get_now();
397
} while (now - start < msecs);
398
}
399
400