summaryrefslogtreecommitdiffstats
path: root/libc-top-half/musl/src/thread/__wait.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc-top-half/musl/src/thread/__wait.c')
-rw-r--r--libc-top-half/musl/src/thread/__wait.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/thread/__wait.c b/libc-top-half/musl/src/thread/__wait.c
new file mode 100644
index 0000000..c0e4aac
--- /dev/null
+++ b/libc-top-half/musl/src/thread/__wait.c
@@ -0,0 +1,55 @@
+#include "pthread_impl.h"
+#ifndef __wasilibc_unmodified_upstream
+#include "assert.h"
+#endif
+
+#ifndef __wasilibc_unmodified_upstream
+// Use WebAssembly's `wait` instruction to implement a futex. Note that `op` is
+// unused but retained as a parameter to match the original signature of the
+// syscall and that, for `max_wait_ns`, -1 (or any negative number) means wait
+// indefinitely.
+//
+// Adapted from Emscripten: see
+// https://github.com/emscripten-core/emscripten/blob/058a9fff/system/lib/pthread/emscripten_futex_wait.c#L111-L150.
+int __wasilibc_futex_wait(volatile void *addr, int op, int val, int64_t max_wait_ns)
+{
+ if ((((intptr_t)addr) & 3) != 0) {
+ return -EINVAL;
+ }
+
+ int ret = __builtin_wasm_memory_atomic_wait32((int *)addr, val, max_wait_ns);
+
+ // memory.atomic.wait32 returns:
+ // 0 => "ok", woken by another agent.
+ // 1 => "not-equal", loaded value != expected value
+ // 2 => "timed-out", the timeout expired
+ if (ret == 1) {
+ return -EWOULDBLOCK;
+ }
+ if (ret == 2) {
+ return -ETIMEDOUT;
+ }
+ assert(ret == 0);
+ return 0;
+}
+#endif
+
+void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
+{
+ int spins=100;
+ if (priv) priv = FUTEX_PRIVATE;
+ while (spins-- && (!waiters || !*waiters)) {
+ if (*addr==val) a_spin();
+ else return;
+ }
+ if (waiters) a_inc(waiters);
+ while (*addr==val) {
+#ifdef __wasilibc_unmodified_upstream
+ __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS
+ || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
+#else
+ __wasilibc_futex_wait(addr, FUTEX_WAIT, val, 0);
+#endif
+ }
+ if (waiters) a_dec(waiters);
+}