Skip to content

Commit 2588bf7

Browse files
committed
internal/task: add cooperative implementation of Futex
See the code comments for details. But in short, this implements a futex for the cooperative scheduler (that is single threaded and non-reentrant). Similar implementations can be made for basically every other operating system, and even WebAssembly with the threading (actually: atomics) proposal. Using this basic futex implementation means we can use the same implementation for synchronisation primitives on cooperative and multicore systems. For more information on futex across operating systems: https://outerproduct.net/futex-dictionary.html
1 parent 72f5645 commit 2588bf7

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package task
2+
3+
// A futex is a way for userspace to wait with the pointer as the key, and for
4+
// another thread to wake one or all waiting threads keyed on the same pointer.
5+
//
6+
// A futex does not change the underlying value, it only reads it before to prevent
7+
// lost wake-ups.
8+
type Futex struct {
9+
Uint32
10+
waiters Stack
11+
}
12+
13+
// Atomically check for cmp to still be equal to the futex value and if so, go
14+
// to sleep. Return true if we were definitely awoken by a call to Wake or
15+
// WakeAll, and false if we can't be sure of that.
16+
func (f *Futex) Wait(cmp uint32) (awoken bool) {
17+
if f.Uint32.v != cmp {
18+
return false
19+
}
20+
21+
// Push the current goroutine onto the waiter stack.
22+
f.waiters.Push(Current())
23+
24+
// Pause until the waiters are awoken by Wake/WakeAll.
25+
Pause()
26+
27+
// We were awoken by a call to Wake or WakeAll. There is no chance for
28+
// spurious wakeups.
29+
return true
30+
}
31+
32+
// Wake a single waiter.
33+
func (f *Futex) Wake() {
34+
if t := f.waiters.Pop(); t != nil {
35+
scheduleTask(t)
36+
}
37+
}
38+
39+
// Wake all waiters.
40+
func (f *Futex) WakeAll() {
41+
for t := f.waiters.Pop(); t != nil; t = f.waiters.Pop() {
42+
scheduleTask(t)
43+
}
44+
}

0 commit comments

Comments
 (0)