Source file
src/runtime/lock_futex.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/runtime/atomic"
11 "unsafe"
12 )
13
14
15
16
17 func key32(p *uintptr) *uint32 {
18 return (*uint32)(unsafe.Pointer(p))
19 }
20
21
22 func noteclear(n *note) {
23 n.key = 0
24 }
25
26 func notewakeup(n *note) {
27 old := atomic.Xchg(key32(&n.key), 1)
28 if old != 0 {
29 print("notewakeup - double wakeup (", old, ")\n")
30 throw("notewakeup - double wakeup")
31 }
32 futexwakeup(key32(&n.key), 1)
33 }
34
35 func notesleep(n *note) {
36 gp := getg()
37 if gp != gp.m.g0 {
38 throw("notesleep not on g0")
39 }
40 ns := int64(-1)
41 if *cgo_yield != nil {
42
43 ns = 10e6
44 }
45 for atomic.Load(key32(&n.key)) == 0 {
46 gp.m.blocked = true
47 futexsleep(key32(&n.key), 0, ns)
48 if *cgo_yield != nil {
49 asmcgocall(*cgo_yield, nil)
50 }
51 gp.m.blocked = false
52 }
53 }
54
55
56
57
58
59
60 func notetsleep_internal(n *note, ns int64) bool {
61 gp := getg()
62
63 if ns < 0 {
64 if *cgo_yield != nil {
65
66 ns = 10e6
67 }
68 for atomic.Load(key32(&n.key)) == 0 {
69 gp.m.blocked = true
70 futexsleep(key32(&n.key), 0, ns)
71 if *cgo_yield != nil {
72 asmcgocall(*cgo_yield, nil)
73 }
74 gp.m.blocked = false
75 }
76 return true
77 }
78
79 if atomic.Load(key32(&n.key)) != 0 {
80 return true
81 }
82
83 deadline := nanotime() + ns
84 for {
85 if *cgo_yield != nil && ns > 10e6 {
86 ns = 10e6
87 }
88 gp.m.blocked = true
89 futexsleep(key32(&n.key), 0, ns)
90 if *cgo_yield != nil {
91 asmcgocall(*cgo_yield, nil)
92 }
93 gp.m.blocked = false
94 if atomic.Load(key32(&n.key)) != 0 {
95 break
96 }
97 now := nanotime()
98 if now >= deadline {
99 break
100 }
101 ns = deadline - now
102 }
103 return atomic.Load(key32(&n.key)) != 0
104 }
105
106 func notetsleep(n *note, ns int64) bool {
107 gp := getg()
108 if gp != gp.m.g0 && gp.m.preemptoff != "" {
109 throw("notetsleep not on g0")
110 }
111
112 return notetsleep_internal(n, ns)
113 }
114
115
116
117 func notetsleepg(n *note, ns int64) bool {
118 gp := getg()
119 if gp == gp.m.g0 {
120 throw("notetsleepg on g0")
121 }
122
123 entersyscallblock()
124 ok := notetsleep_internal(n, ns)
125 exitsyscall()
126 return ok
127 }
128
129 func beforeIdle(int64, int64) (*g, bool) {
130 return nil, false
131 }
132
133 func checkTimeouts() {}
134
135
136 func semacreate(mp *m) {}
137
138
139 func semasleep(ns int64) int32 {
140 mp := getg().m
141
142 for v := atomic.Xadd(&mp.waitsema, -1); ; v = atomic.Load(&mp.waitsema) {
143 if int32(v) >= 0 {
144 return 0
145 }
146 futexsleep(&mp.waitsema, v, ns)
147 if ns >= 0 {
148 if int32(v) >= 0 {
149 return 0
150 } else {
151 return -1
152 }
153 }
154 }
155 }
156
157
158 func semawakeup(mp *m) {
159 v := atomic.Xadd(&mp.waitsema, 1)
160 if v == 0 {
161 futexwakeup(&mp.waitsema, 1)
162 }
163 }
164
View as plain text