Skip to content

Commit

Permalink
internal/task: add cooperative implementation of Futex
Browse files Browse the repository at this point in the history
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
  • Loading branch information
aykevl committed Dec 1, 2024
1 parent 67a3283 commit 390c4e8
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/internal/task/futex-cooperative.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package task

// A futex is a way for userspace to wait with the pointer as the key, and for
// another thread to wake one or all waiting threads keyed on the same pointer.
//
// A futex does not change the underlying value, it only reads it before to prevent
// lost wake-ups.
type Futex struct {
Uint32
waiters Stack
}

// Atomically check for cmp to still be equal to the futex value and if so, go
// to sleep. Return true if we were definitely awoken by a call to Wake or
// WakeAll, and false if we can't be sure of that.
func (f *Futex) Wait(cmp uint32) (awoken bool) {
if f.Uint32.v != cmp {
return false
}

// Push the current goroutine onto the waiter stack.
f.waiters.Push(Current())

// Pause until the waiters are awoken by Wake/WakeAll.
Pause()

// We were awoken by a call to Wake or WakeAll. There is no chance for
// spurious wakeups.
return true
}

// Wake a single waiter.
func (f *Futex) Wake() {
if t := f.waiters.Pop(); t != nil {
scheduleTask(t)
}
}

// Wake all waiters.
func (f *Futex) WakeAll() {
for t := f.waiters.Pop(); t != nil; t = f.waiters.Pop() {
scheduleTask(t)
}
}

0 comments on commit 390c4e8

Please sign in to comment.