| ... | @@ -73,6 +73,8 @@ else if (builtin.os.tag == .openbsd) | ... | @@ -73,6 +73,8 @@ else if (builtin.os.tag == .openbsd) |
| 73 | OpenbsdImpl | 73 | OpenbsdImpl |
| 74 | else if (builtin.os.tag == .dragonfly) | 74 | else if (builtin.os.tag == .dragonfly) |
| 75 | DragonflyImpl | 75 | DragonflyImpl |
| | 76 | else if (builtin.target.isWasm()) |
| | 77 | WasmImpl |
| 76 | else if (std.Thread.use_pthreads) | 78 | else if (std.Thread.use_pthreads) |
| 77 | PosixImpl | 79 | PosixImpl |
| 78 | else | 80 | else |
| ... | @@ -446,6 +448,49 @@ const DragonflyImpl = struct { | ... | @@ -446,6 +448,49 @@ const DragonflyImpl = struct { |
| 446 | } | 448 | } |
| 447 | }; | 449 | }; |
| 448 | | 450 | |
| | 451 | const 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.html | 495 | /// https://code.woboq.org/linux/linux/kernel/futex.c.html |
| 451 | /// https://go.dev/src/runtime/sema.go | 496 | /// https://go.dev/src/runtime/sema.go |