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