Source file
src/runtime/lockrank_on.go
Documentation: runtime
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "runtime/internal/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 func acquireLockRank(rank lockRank) {
113 gp := getg()
114
115 systemstack(func() {
116 i := gp.m.locksHeldLen
117 if i >= len(gp.m.locksHeld) {
118 throw("too many locks held concurrently for rank checking")
119 }
120 gp.m.locksHeld[i].rank = rank
121 gp.m.locksHeld[i].lockAddr = 0
122 gp.m.locksHeldLen++
123
124
125 if i > 0 {
126 checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
127 }
128 })
129 }
130
131
132
133
134
135 func checkRanks(gp *g, prevRank, rank lockRank) {
136 rankOK := false
137 if rank < prevRank {
138
139 rankOK = false
140 } else if rank == lockRankLeafRank {
141
142
143 rankOK = prevRank < lockRankLeafRank
144 } else {
145
146
147
148
149
150 list := lockPartialOrder[rank]
151 for _, entry := range list {
152 if entry == prevRank {
153 rankOK = true
154 break
155 }
156 }
157 }
158 if !rankOK {
159 printlock()
160 println(gp.m.procid, " ======")
161 printHeldLocks(gp)
162 throw("lock ordering problem")
163 }
164 }
165
166
167 func unlockWithRank(l *mutex) {
168 if l == &debuglock || l == &paniclk || l == &raceFiniLock {
169
170 unlock2(l)
171 return
172 }
173 gp := getg()
174 systemstack(func() {
175 found := false
176 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
177 if gp.m.locksHeld[i].lockAddr == uintptr(unsafe.Pointer(l)) {
178 found = true
179 copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
180 gp.m.locksHeldLen--
181 break
182 }
183 }
184 if !found {
185 println(gp.m.procid, ":", l.rank.String(), l.rank, l)
186 throw("unlock without matching lock acquire")
187 }
188 unlock2(l)
189 })
190 }
191
192
193
194
195
196
197 func releaseLockRank(rank lockRank) {
198 gp := getg()
199 systemstack(func() {
200 found := false
201 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
202 if gp.m.locksHeld[i].rank == rank && gp.m.locksHeld[i].lockAddr == 0 {
203 found = true
204 copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
205 gp.m.locksHeldLen--
206 break
207 }
208 }
209 if !found {
210 println(gp.m.procid, ":", rank.String(), rank)
211 throw("lockRank release without matching lockRank acquire")
212 }
213 })
214 }
215
216
217
218
219 func lockWithRankMayAcquire(l *mutex, rank lockRank) {
220 gp := getg()
221 if gp.m.locksHeldLen == 0 {
222
223 return
224 }
225
226 systemstack(func() {
227 i := gp.m.locksHeldLen
228 if i >= len(gp.m.locksHeld) {
229 throw("too many locks held concurrently for rank checking")
230 }
231
232
233
234 gp.m.locksHeld[i].rank = rank
235 gp.m.locksHeld[i].lockAddr = uintptr(unsafe.Pointer(l))
236 gp.m.locksHeldLen++
237 checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
238 gp.m.locksHeldLen--
239 })
240 }
241
242
243
244
245 func checkLockHeld(gp *g, l *mutex) bool {
246 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
247 if gp.m.locksHeld[i].lockAddr == uintptr(unsafe.Pointer(l)) {
248 return true
249 }
250 }
251 return false
252 }
253
254
255
256
257
258
259 func assertLockHeld(l *mutex) {
260 gp := getg()
261
262 held := checkLockHeld(gp, l)
263 if held {
264 return
265 }
266
267
268
269 systemstack(func() {
270 printlock()
271 print("caller requires lock ", l, " (rank ", l.rank.String(), "), holding:\n")
272 printHeldLocks(gp)
273 throw("not holding required lock!")
274 })
275 }
276
277
278
279
280
281
282
283
284
285 func assertRankHeld(r lockRank) {
286 gp := getg()
287
288 for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
289 if gp.m.locksHeld[i].rank == r {
290 return
291 }
292 }
293
294
295
296 systemstack(func() {
297 printlock()
298 print("caller requires lock with rank ", r.String(), "), holding:\n")
299 printHeldLocks(gp)
300 throw("not holding required lock!")
301 })
302 }
303
304
305
306
307
308
309
310
311 func worldStopped() {
312 if stopped := worldIsStopped.Add(1); stopped != 1 {
313 systemstack(func() {
314 print("world stop count=", stopped, "\n")
315 throw("recursive world stop")
316 })
317 }
318 }
319
320
321
322
323
324
325
326
327 func worldStarted() {
328 if stopped := worldIsStopped.Add(-1); stopped != 0 {
329 systemstack(func() {
330 print("world stop count=", stopped, "\n")
331 throw("released non-stopped world stop")
332 })
333 }
334 }
335
336
337
338
339 func checkWorldStopped() bool {
340 stopped := worldIsStopped.Load()
341 if stopped > 1 {
342 systemstack(func() {
343 print("inconsistent world stop count=", stopped, "\n")
344 throw("inconsistent world stop count")
345 })
346 }
347
348 return stopped == 1
349 }
350
351
352
353
354
355
356
357 func assertWorldStopped() {
358 if checkWorldStopped() {
359 return
360 }
361
362 throw("world not stopped")
363 }
364
365
366
367
368
369
370
371 func assertWorldStoppedOrLockHeld(l *mutex) {
372 if checkWorldStopped() {
373 return
374 }
375
376 gp := getg()
377 held := checkLockHeld(gp, l)
378 if held {
379 return
380 }
381
382
383
384 systemstack(func() {
385 printlock()
386 print("caller requires world stop or lock ", l, " (rank ", l.rank.String(), "), holding:\n")
387 println("<no world stop>")
388 printHeldLocks(gp)
389 throw("no world stop or required lock!")
390 })
391 }
392
View as plain text