-
Notifications
You must be signed in to change notification settings - Fork 114
/
Copy pathlock.go
96 lines (85 loc) · 1.87 KB
/
lock.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package kernel
import (
"unsafe"
"gvisor.dev/gvisor/pkg/abi/linux"
)
const (
_FUTEX_WAIT = 0
_FUTEX_WAKE = 1
_FUTEX_PRIVATE_FLAG = 128
_FUTEX_WAIT_PRIVATE = _FUTEX_WAIT | _FUTEX_PRIVATE_FLAG
_FUTEX_WAKE_PRIVATE = _FUTEX_WAKE | _FUTEX_PRIVATE_FLAG
)
//go:nosplit
func futex(addr *uintptr, op, val uintptr, ts *linux.Timespec) {
switch op {
case _FUTEX_WAIT, _FUTEX_WAIT_PRIVATE:
if ts != nil {
sleeptimeout(addr, val, ts)
return
}
for *addr == val {
sleepon(addr)
}
return
case _FUTEX_WAKE, _FUTEX_WAKE_PRIVATE:
wakeup(addr, int(val))
default:
panic("futex: invalid op")
}
}
//go:nosplit
func sleeptimeout(addr *uintptr, val uintptr, ts *linux.Timespec) {
if ts == nil {
panic("sleeptimeout: nil ts")
}
deadline := nanosecond() + int64(ts.Nsec) + int64(ts.Sec)*second
// check on every timer intr
now := nanosecond()
t := Mythread()
for now < deadline && *addr == val {
t.timerKey = uintptr(unsafe.Pointer(&sleeplock))
t.sleepKey = uintptr(unsafe.Pointer(addr))
t.state = SLEEPING
Sched()
t.timerKey = 0
t.sleepKey = 0
now = nanosecond()
}
}
//go:nosplit
func sleepon(lock *uintptr) {
t := Mythread()
t.sleepKey = uintptr(unsafe.Pointer(lock))
t.state = SLEEPING
Sched()
t.sleepKey = 0
}
// wakeup thread sleep on lock, n == -1 means all threads
//go:nosplit
func wakeup(lock *uintptr, n int) {
limit := uint(n)
cnt := uint(0)
lockKey := uintptr(unsafe.Pointer(lock))
for i := 0; i < _NTHREDS; i++ {
t := &threads[i]
if (t.sleepKey == lockKey || t.timerKey == lockKey) && cnt < limit {
cnt++
t.state = RUNNABLE
}
}
}
type note uintptr
//go:nosplit
func (n *note) sleep(ts *linux.Timespec) {
futex((*uintptr)(unsafe.Pointer(n)), _FUTEX_WAIT, 0, ts)
}
//go:nosplit
func (n *note) wakeup() {
*n = 1
futex((*uintptr)(unsafe.Pointer(n)), _FUTEX_WAKE, 1, nil)
}
//go:nosplit
func (n *note) clear() {
*n = 0
}