Source file
src/runtime/lockrank_on.go
Documentation: runtime
1
2
3
4
5
6
7
8 package runtime
9
10 import (
11 "runtime/internal/atomic"
12 "unsafe"
13 )
14
15
16
17 var worldIsStopped uint32
18
19
20 type lockRankStruct struct {
21
22 rank lockRank
23
24
25 pad int
26 }
27
28 func lockInit(l *mutex, rank lockRank) {
29 l.rank = rank
30 }
31
32 func getLockRank(l *mutex) lockRank {
33 return l.rank
34 }
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 func lockWithRank(l *mutex, rank lockRank) {
50 if l == &debuglock || l == &paniclk {
51
52
53
54
55
56
57
58
59
60 lock2(l)
61 return
62 }
63 if rank == 0 {
64 rank = lockRankLeafRank
65 }
66 gp := getg()
67
68 systemstack(func() {
69 i := gp.m.locksHeldLen
70 if i >= len(gp.m.locksHeld) {
71 throw("too many locks held concurrently for rank checking")
72 }
73 gp.m.locksHeld[i].rank = rank
74 gp.m.locksHeld[i].lockAddr = uintptr(unsafe.Pointer(l))
75 gp.m.locksHeldLen++
76
77
78 if i > 0 {
79 checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
80 }
81 lock2(l)
82 })
83 }
84
85
86
87 func printHeldLocks(gp *g) {
88 if gp.m.locksHeldLen == 0 {
89 println("<none>")
90 return
91 }
92
93 for j, held := range gp.m.locksHeld[:gp.m.locksHeldLen] {
94 println(j, ":", held.rank.String(), held.rank, unsafe.Pointer(gp.m.locksHeld[j].lockAddr))
95 }
96 }
97
98
99
100
101
102 func acquireLockRank(rank lockRank) {
103 gp := getg()
104
105 systemstack(func() {
106 i := gp.m.locksHeldLen
107 if i >= len(gp.m.locksHeld) {
108 throw("too many locks held concurrently for rank checking")
109 }
110 gp.m.locksHeld[i].rank = rank
111 gp.m.locksHeld[i].lockAddr = 0
112 gp.m.locksHeldLen++
113
114
115 if i > 0 {
116 checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
117 }
118 })
119 }
120
121
122
123
124
125 func checkRanks(gp *g, prevRank, rank lockRank) {
126 rankOK := false
127 if rank < prevRank {
128
129 rankOK = false
130 } else if rank == lockRankLeafRank {
131
132
133 rankOK = prevRank < lockRankLeafRank
134 } else {
135
136
137
138
139
140 list := lockPartialOrder[rank]
141 for _, entry := range list {
142 if entry == prevRank {
143 rankOK = true
144 break
145 }
146 }
147 }
148 if !rankOK {
149 printlock()
150 println(gp.m.procid, " ======")
151 printHeldLocks(gp)
152 throw("lock ordering problem")
153 }
154 }
155
156
157 func unlockWithRank(l *mutex) {
158 if l == &debuglock || l == &paniclk {
159
160 unlock2(l)
161 return
162 }
163 gp := getg()
164 systemstack(func() {
165 found := false
166 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
167 if gp.m.locksHeld[i].lockAddr == uintptr(unsafe.Pointer(l)) {
168 found = true
169 copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
170 gp.m.locksHeldLen--
171 break
172 }
173 }
174 if !found {
175 println(gp.m.procid, ":", l.rank.String(), l.rank, l)
176 throw("unlock without matching lock acquire")
177 }
178 unlock2(l)
179 })
180 }
181
182
183
184
185
186 func releaseLockRank(rank lockRank) {
187 gp := getg()
188 systemstack(func() {
189 found := false
190 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
191 if gp.m.locksHeld[i].rank == rank && gp.m.locksHeld[i].lockAddr == 0 {
192 found = true
193 copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
194 gp.m.locksHeldLen--
195 break
196 }
197 }
198 if !found {
199 println(gp.m.procid, ":", rank.String(), rank)
200 throw("lockRank release without matching lockRank acquire")
201 }
202 })
203 }
204
205
206 func lockWithRankMayAcquire(l *mutex, rank lockRank) {
207 gp := getg()
208 if gp.m.locksHeldLen == 0 {
209
210 return
211 }
212
213 systemstack(func() {
214 i := gp.m.locksHeldLen
215 if i >= len(gp.m.locksHeld) {
216 throw("too many locks held concurrently for rank checking")
217 }
218
219
220
221 gp.m.locksHeld[i].rank = rank
222 gp.m.locksHeld[i].lockAddr = uintptr(unsafe.Pointer(l))
223 gp.m.locksHeldLen++
224 checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
225 gp.m.locksHeldLen--
226 })
227 }
228
229
230
231 func checkLockHeld(gp *g, l *mutex) bool {
232 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
233 if gp.m.locksHeld[i].lockAddr == uintptr(unsafe.Pointer(l)) {
234 return true
235 }
236 }
237 return false
238 }
239
240
241
242
243
244 func assertLockHeld(l *mutex) {
245 gp := getg()
246
247 held := checkLockHeld(gp, l)
248 if held {
249 return
250 }
251
252
253
254 systemstack(func() {
255 printlock()
256 print("caller requires lock ", l, " (rank ", l.rank.String(), "), holding:\n")
257 printHeldLocks(gp)
258 throw("not holding required lock!")
259 })
260 }
261
262
263
264
265
266
267
268
269 func assertRankHeld(r lockRank) {
270 gp := getg()
271
272 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
273 if gp.m.locksHeld[i].rank == r {
274 return
275 }
276 }
277
278
279
280 systemstack(func() {
281 printlock()
282 print("caller requires lock with rank ", r.String(), "), holding:\n")
283 printHeldLocks(gp)
284 throw("not holding required lock!")
285 })
286 }
287
288
289
290
291
292
293
294 func worldStopped() {
295 if stopped := atomic.Xadd(&worldIsStopped, 1); stopped != 1 {
296 systemstack(func() {
297 print("world stop count=", stopped, "\n")
298 throw("recursive world stop")
299 })
300 }
301 }
302
303
304
305
306
307
308
309 func worldStarted() {
310 if stopped := atomic.Xadd(&worldIsStopped, -1); stopped != 0 {
311 systemstack(func() {
312 print("world stop count=", stopped, "\n")
313 throw("released non-stopped world stop")
314 })
315 }
316 }
317
318
319
320 func checkWorldStopped() bool {
321 stopped := atomic.Load(&worldIsStopped)
322 if stopped > 1 {
323 systemstack(func() {
324 print("inconsistent world stop count=", stopped, "\n")
325 throw("inconsistent world stop count")
326 })
327 }
328
329 return stopped == 1
330 }
331
332
333
334
335
336
337 func assertWorldStopped() {
338 if checkWorldStopped() {
339 return
340 }
341
342 throw("world not stopped")
343 }
344
345
346
347
348
349
350 func assertWorldStoppedOrLockHeld(l *mutex) {
351 if checkWorldStopped() {
352 return
353 }
354
355 gp := getg()
356 held := checkLockHeld(gp, l)
357 if held {
358 return
359 }
360
361
362
363 systemstack(func() {
364 printlock()
365 print("caller requires world stop or lock ", l, " (rank ", l.rank.String(), "), holding:\n")
366 println("<no world stop>")
367 printHeldLocks(gp)
368 throw("no world stop or required lock!")
369 })
370 }
371
View as plain text