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
18
19
20
21
22
23
24
25 const (
26 mutex_unlocked = 0
27 mutex_locked = 1
28 mutex_sleeping = 2
29
30 active_spin = 4
31 active_spin_cnt = 30
32 passive_spin = 1
33 )
34
35
36
37
38
39
40
41
42
43 func key32(p *uintptr) *uint32 {
44 return (*uint32)(unsafe.Pointer(p))
45 }
46
47 func mutexContended(l *mutex) bool {
48 return atomic.Load(key32(&l.key)) > mutex_locked
49 }
50
51 func lock(l *mutex) {
52 lockWithRank(l, getLockRank(l))
53 }
54
55 func lock2(l *mutex) {
56 gp := getg()
57
58 if gp.m.locks < 0 {
59 throw("runtime·lock: lock count")
60 }
61 gp.m.locks++
62
63
64 v := atomic.Xchg(key32(&l.key), mutex_locked)
65 if v == mutex_unlocked {
66 return
67 }
68
69
70
71
72
73
74
75
76 wait := v
77
78 timer := &lockTimer{lock: l}
79 timer.begin()
80
81
82 spin := 0
83 if ncpu > 1 {
84 spin = active_spin
85 }
86 for {
87
88 for i := 0; i < spin; i++ {
89 for l.key == mutex_unlocked {
90 if atomic.Cas(key32(&l.key), mutex_unlocked, wait) {
91 timer.end()
92 return
93 }
94 }
95 procyield(active_spin_cnt)
96 }
97
98
99 for i := 0; i < passive_spin; i++ {
100 for l.key == mutex_unlocked {
101 if atomic.Cas(key32(&l.key), mutex_unlocked, wait) {
102 timer.end()
103 return
104 }
105 }
106 osyield()
107 }
108
109
110 v = atomic.Xchg(key32(&l.key), mutex_sleeping)
111 if v == mutex_unlocked {
112 timer.end()
113 return
114 }
115 wait = mutex_sleeping
116 futexsleep(key32(&l.key), mutex_sleeping, -1)
117 }
118 }
119
120 func unlock(l *mutex) {
121 unlockWithRank(l)
122 }
123
124 func unlock2(l *mutex) {
125 v := atomic.Xchg(key32(&l.key), mutex_unlocked)
126 if v == mutex_unlocked {
127 throw("unlock of unlocked lock")
128 }
129 if v == mutex_sleeping {
130 futexwakeup(key32(&l.key), 1)
131 }
132
133 gp := getg()
134 gp.m.mLockProfile.recordUnlock(l)
135 gp.m.locks--
136 if gp.m.locks < 0 {
137 throw("runtime·unlock: lock count")
138 }
139 if gp.m.locks == 0 && gp.preempt {
140 gp.stackguard0 = stackPreempt
141 }
142 }
143
144
145 func noteclear(n *note) {
146 n.key = 0
147 }
148
149 func notewakeup(n *note) {
150 old := atomic.Xchg(key32(&n.key), 1)
151 if old != 0 {
152 print("notewakeup - double wakeup (", old, ")\n")
153 throw("notewakeup - double wakeup")
154 }
155 futexwakeup(key32(&n.key), 1)
156 }
157
158 func notesleep(n *note) {
159 gp := getg()
160 if gp != gp.m.g0 {
161 throw("notesleep not on g0")
162 }
163 ns := int64(-1)
164 if *cgo_yield != nil {
165
166 ns = 10e6
167 }
168 for atomic.Load(key32(&n.key)) == 0 {
169 gp.m.blocked = true
170 futexsleep(key32(&n.key), 0, ns)
171 if *cgo_yield != nil {
172 asmcgocall(*cgo_yield, nil)
173 }
174 gp.m.blocked = false
175 }
176 }
177
178
179
180
181
182
183 func notetsleep_internal(n *note, ns int64) bool {
184 gp := getg()
185
186 if ns < 0 {
187 if *cgo_yield != nil {
188
189 ns = 10e6
190 }
191 for atomic.Load(key32(&n.key)) == 0 {
192 gp.m.blocked = true
193 futexsleep(key32(&n.key), 0, ns)
194 if *cgo_yield != nil {
195 asmcgocall(*cgo_yield, nil)
196 }
197 gp.m.blocked = false
198 }
199 return true
200 }
201
202 if atomic.Load(key32(&n.key)) != 0 {
203 return true
204 }
205
206 deadline := nanotime() + ns
207 for {
208 if *cgo_yield != nil && ns > 10e6 {
209 ns = 10e6
210 }
211 gp.m.blocked = true
212 futexsleep(key32(&n.key), 0, ns)
213 if *cgo_yield != nil {
214 asmcgocall(*cgo_yield, nil)
215 }
216 gp.m.blocked = false
217 if atomic.Load(key32(&n.key)) != 0 {
218 break
219 }
220 now := nanotime()
221 if now >= deadline {
222 break
223 }
224 ns = deadline - now
225 }
226 return atomic.Load(key32(&n.key)) != 0
227 }
228
229 func notetsleep(n *note, ns int64) bool {
230 gp := getg()
231 if gp != gp.m.g0 && gp.m.preemptoff != "" {
232 throw("notetsleep not on g0")
233 }
234
235 return notetsleep_internal(n, ns)
236 }
237
238
239
240 func notetsleepg(n *note, ns int64) bool {
241 gp := getg()
242 if gp == gp.m.g0 {
243 throw("notetsleepg on g0")
244 }
245
246 entersyscallblock()
247 ok := notetsleep_internal(n, ns)
248 exitsyscall()
249 return ok
250 }
251
252 func beforeIdle(int64, int64) (*g, bool) {
253 return nil, false
254 }
255
256 func checkTimeouts() {}
257
View as plain text