From ea0d4c8377aeabe1ef588e82cbdd9aa729adbce0 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 19 Jun 2023 12:10:32 +0200 Subject: [PATCH] std: implement `Futex` for WebAssembly Implements std's `Futex` for the WebAssembly target using Wasm's `atomics` instruction set. When the `atomics` cpu feature is disabled we emit a compile-error. --- lib/std/Thread/Futex.zig | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lib/std/Thread/Futex.zig b/lib/std/Thread/Futex.zig index 768442539b..2fe4120f68 100644 --- a/lib/std/Thread/Futex.zig +++ b/lib/std/Thread/Futex.zig @@ -73,6 +73,8 @@ else if (builtin.os.tag == .openbsd) OpenbsdImpl else if (builtin.os.tag == .dragonfly) DragonflyImpl +else if (builtin.target.isWasm()) + WasmImpl else if (std.Thread.use_pthreads) PosixImpl else @@ -446,6 +448,49 @@ const DragonflyImpl = struct { } }; +const WasmImpl = struct { + fn wait(ptr: *const Atomic(u32), expect: u32, timeout: ?u64) error{Timeout}!void { + if (!comptime std.Target.wasm.featureSetHas(builtin.target.cpu.features, .atomics)) { + @compileError("WASI target missing cpu feature 'atomics'"); + } + const to: i64 = if (timeout) |to| @intCast(i64, to) else -1; + const result = asm ( + \\local.get %[ptr] + \\local.get %[expected] + \\local.get %[timeout] + \\memory.atomic.wait32 0 + \\local.set %[ret] + : [ret] "=r" (-> u32), + : [ptr] "r" (&ptr.value), + [expected] "r" (@bitCast(i32, expect)), + [timeout] "r" (to), + ); + switch (result) { + 0 => {}, // ok + 1 => {}, // expected =! loaded + 2 => return error.Timeout, + else => unreachable, + } + } + + fn wake(ptr: *const Atomic(u32), max_waiters: u32) void { + if (!comptime std.Target.wasm.featureSetHas(builtin.target.cpu.features, .atomics)) { + @compileError("WASI target missing cpu feature 'atomics'"); + } + assert(max_waiters != 0); + const woken_count = asm ( + \\local.get %[ptr] + \\local.get %[waiters] + \\memory.atomic.notify 0 + \\local.set %[ret] + : [ret] "=r" (-> u32), + : [ptr] "r" (&ptr.value), + [waiters] "r" (max_waiters), + ); + _ = woken_count; // can be 0 when linker flag 'shared-memory' is not enabled + } +}; + /// Modified version of linux's futex and Go's sema to implement userspace wait queues with pthread: /// https://code.woboq.org/linux/linux/kernel/futex.c.html /// https://go.dev/src/runtime/sema.go