]> git.proxmox.com Git - wasi-libc.git/blob - libc-top-half/musl/src/thread/__wait.c
threads: implement support for pthread mutexes (#315)
[wasi-libc.git] / libc-top-half / musl / src / thread / __wait.c
1 #include "pthread_impl.h"
2 #ifndef __wasilibc_unmodified_upstream
3 #include "assert.h"
4 #endif
5
6 #ifndef __wasilibc_unmodified_upstream
7 // Use WebAssembly's `wait` instruction to implement a futex. Note that `op` is
8 // unused but retained as a parameter to match the original signature of the
9 // syscall and that, for `max_wait_ns`, -1 (or any negative number) means wait
10 // indefinitely.
11 //
12 // Adapted from Emscripten: see
13 // https://github.com/emscripten-core/emscripten/blob/058a9fff/system/lib/pthread/emscripten_futex_wait.c#L111-L150.
14 int __wasilibc_futex_wait(volatile void *addr, int op, int val, int64_t max_wait_ns)
15 {
16 if ((((intptr_t)addr) & 3) != 0) {
17 return -EINVAL;
18 }
19
20 int ret = __builtin_wasm_memory_atomic_wait32((int *)addr, val, max_wait_ns);
21
22 // memory.atomic.wait32 returns:
23 // 0 => "ok", woken by another agent.
24 // 1 => "not-equal", loaded value != expected value
25 // 2 => "timed-out", the timeout expired
26 if (ret == 1) {
27 return -EWOULDBLOCK;
28 }
29 if (ret == 2) {
30 return -ETIMEDOUT;
31 }
32 assert(ret == 0);
33 return 0;
34 }
35 #endif
36
37 void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
38 {
39 int spins=100;
40 if (priv) priv = FUTEX_PRIVATE;
41 while (spins-- && (!waiters || !*waiters)) {
42 if (*addr==val) a_spin();
43 else return;
44 }
45 if (waiters) a_inc(waiters);
46 while (*addr==val) {
47 #ifdef __wasilibc_unmodified_upstream
48 __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS
49 || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
50 #else
51 __wasilibc_futex_wait(addr, FUTEX_WAIT, val, 0);
52 #endif
53 }
54 if (waiters) a_dec(waiters);
55 }