-
Notifications
You must be signed in to change notification settings - Fork 946
/
Copy pathfutex-cores.go
64 lines (50 loc) · 1.44 KB
/
futex-cores.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//go:build scheduler.cores
package task
import "runtime/interrupt"
// 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) {
mask := lockFutex()
if f.Uint32.Load() != cmp {
unlockFutex(mask)
return false
}
// Push the current goroutine onto the waiter stack.
f.waiters.Push(Current())
unlockFutex(mask)
// Pause until this task is 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() {
mask := lockFutex()
if t := f.waiters.Pop(); t != nil {
scheduleTask(t)
}
unlockFutex(mask)
}
// Wake all waiters.
func (f *Futex) WakeAll() {
mask := lockFutex()
for t := f.waiters.Pop(); t != nil; t = f.waiters.Pop() {
scheduleTask(t)
}
unlockFutex(mask)
}
//go:linkname lockFutex runtime.lockFutex
func lockFutex() interrupt.State
//go:linkname unlockFutex runtime.unlockFutex
func unlockFutex(interrupt.State)