1 package futex
2 3 // Cross platform futex implementation.
4 // Futexes are supported on all major operating systems and on WebAssembly.
5 //
6 // For more information, see: https://outerproduct.net/futex-dictionary.html
7 8 import (
9 "sync/atomic"
10 "unsafe"
11 )
12 13 // A futex is a way for userspace to wait with the pointer as the key, and for
14 // another thread to wake one or all waiting threads keyed on the same pointer.
15 //
16 // A futex does not change the underlying value, it only reads it before going
17 // to sleep (atomically) to prevent lost wake-ups.
18 type Futex struct {
19 atomic.Uint32
20 }
21 22 // Atomically check for cmp to still be equal to the futex value and if so, go
23 // to sleep. Return true if we were definitely awoken by a call to Wake or
24 // WakeAll, and false if we can't be sure of that.
25 func (f *Futex) Wait(cmp uint32) bool {
26 moxie_futex_wait((*uint32)(unsafe.Pointer(&f.Uint32)), cmp)
27 28 // We *could* detect a zero return value from the futex system call which
29 // would indicate we got awoken by a Wake or WakeAll call. However, this is
30 // what the manual page has to say:
31 //
32 // > Note that a wake-up can also be caused by common futex usage patterns
33 // > in unrelated code that happened to have previously used the futex
34 // > word's memory location (e.g., typical futex-based implementations of
35 // > Pthreads mutexes can cause this under some conditions). Therefore,
36 // > callers should always conservatively assume that a return value of 0
37 // > can mean a spurious wake-up, and use the futex word's value (i.e., the
38 // > user-space synchronization scheme) to decide whether to continue to
39 // > block or not.
40 //
41 // I'm not sure whether we do anything like pthread does, so to be on the
42 // safe side we say we don't know whether the wakeup was spurious or not and
43 // return false.
44 return false
45 }
46 47 // Like Wait, but times out after the number of nanoseconds in timeout.
48 func (f *Futex) WaitUntil(cmp uint32, timeout uint64) {
49 moxie_futex_wait_timeout((*uint32)(unsafe.Pointer(&f.Uint32)), cmp, timeout)
50 }
51 52 // Wake a single waiter.
53 func (f *Futex) Wake() {
54 moxie_futex_wake((*uint32)(unsafe.Pointer(&f.Uint32)))
55 }
56 57 // Wake all waiters.
58 func (f *Futex) WakeAll() {
59 moxie_futex_wake_all((*uint32)(unsafe.Pointer(&f.Uint32)))
60 }
61 62 //export moxie_futex_wait
63 func moxie_futex_wait(addr *uint32, cmp uint32)
64 65 //export moxie_futex_wait_timeout
66 func moxie_futex_wait_timeout(addr *uint32, cmp uint32, timeout uint64)
67 68 //export moxie_futex_wake
69 func moxie_futex_wake(addr *uint32)
70 71 //export moxie_futex_wake_all
72 func moxie_futex_wake_all(addr *uint32)
73