authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-06-19 12:10:32+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-06-26 20:00:57+02:00
logea0d4c8377aeabe1ef588e82cbdd9aa729adbce0
tree3da8d930fcd180b72053ea25cfa081d52084d8ac
parent062eb6f3c0027e8a371e6865963645b70e49b84e
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 45 insertions(+), 0 deletions(-)

lib/std/Thread/Futex.zig+45
...@@ -73,6 +73,8 @@ else if (builtin.os.tag == .openbsd)...@@ -73,6 +73,8 @@ else if (builtin.os.tag == .openbsd)
73 OpenbsdImpl73 OpenbsdImpl
74else if (builtin.os.tag == .dragonfly)74else if (builtin.os.tag == .dragonfly)
75 DragonflyImpl75 DragonflyImpl
76else if (builtin.target.isWasm())
77 WasmImpl
76else if (std.Thread.use_pthreads)78else if (std.Thread.use_pthreads)
77 PosixImpl79 PosixImpl
78else80else
...@@ -446,6 +448,49 @@ const DragonflyImpl = struct {...@@ -446,6 +448,49 @@ const DragonflyImpl = struct {
446 }448 }
447};449};
448450
451const WasmImpl = struct {
452 fn wait(ptr: *const Atomic(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
453 if (!comptime std.Target.wasm.featureSetHas(builtin.target.cpu.features, .atomics)) {
454 @compileError("WASI target missing cpu feature 'atomics'");
455 }
456 const to: i64 = if (timeout) |to| @intCast(i64, to) else -1;
457 const result = asm (
458 \\local.get %[ptr]
459 \\local.get %[expected]
460 \\local.get %[timeout]
461 \\memory.atomic.wait32 0
462 \\local.set %[ret]
463 : [ret] "=r" (-> u32),
464 : [ptr] "r" (&ptr.value),
465 [expected] "r" (@bitCast(i32, expect)),
466 [timeout] "r" (to),
467 );
468 switch (result) {
469 0 => {}, // ok
470 1 => {}, // expected =! loaded
471 2 => return error.Timeout,
472 else => unreachable,
473 }
474 }
475
476 fn wake(ptr: *const Atomic(u32), max_waiters: u32) void {
477 if (!comptime std.Target.wasm.featureSetHas(builtin.target.cpu.features, .atomics)) {
478 @compileError("WASI target missing cpu feature 'atomics'");
479 }
480 assert(max_waiters != 0);
481 const woken_count = asm (
482 \\local.get %[ptr]
483 \\local.get %[waiters]
484 \\memory.atomic.notify 0
485 \\local.set %[ret]
486 : [ret] "=r" (-> u32),
487 : [ptr] "r" (&ptr.value),
488 [waiters] "r" (max_waiters),
489 );
490 _ = woken_count; // can be 0 when linker flag 'shared-memory' is not enabled
491 }
492};
493
449/// Modified version of linux's futex and Go's sema to implement userspace wait queues with pthread:494/// Modified version of linux's futex and Go's sema to implement userspace wait queues with pthread:
450/// https://code.woboq.org/linux/linux/kernel/futex.c.html495/// https://code.woboq.org/linux/linux/kernel/futex.c.html
451/// https://go.dev/src/runtime/sema.go496/// https://go.dev/src/runtime/sema.go