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