...
Source file
src/runtime/lock_sema.go
Documentation: runtime
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
26 const (
27 locked uintptr = 1
28
29 active_spin = 4
30 active_spin_cnt = 30
31 passive_spin = 1
32 )
33
34 func mutexContended(l *mutex) bool {
35 return atomic.Loaduintptr(&l.key) > locked
36 }
37
38 func lock(l *mutex) {
39 lockWithRank(l, getLockRank(l))
40 }
41
42 func lock2(l *mutex) {
43 gp := getg()
44 if gp.m.locks < 0 {
45 throw("runtime·lock: lock count")
46 }
47 gp.m.locks++
48
49
50 if atomic.Casuintptr(&l.key, 0, locked) {
51 return
52 }
53 semacreate(gp.m)
54
55 timer := &lockTimer{lock: l}
56 timer.begin()
57
58
59 spin := 0
60 if ncpu > 1 {
61 spin = active_spin
62 }
63 Loop:
64 for i := 0; ; i++ {
65 v := atomic.Loaduintptr(&l.key)
66 if v&locked == 0 {
67
68 if atomic.Casuintptr(&l.key, v, v|locked) {
69 timer.end()
70 return
71 }
72 i = 0
73 }
74 if i < spin {
75 procyield(active_spin_cnt)
76 } else if i < spin+passive_spin {
77 osyield()
78 } else {
79
80
81
82
83 for {
84 gp.m.nextwaitm = muintptr(v &^ locked)
85 if atomic.Casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|locked) {
86 break
87 }
88 v = atomic.Loaduintptr(&l.key)
89 if v&locked == 0 {
90 continue Loop
91 }
92 }
93 if v&locked != 0 {
94
95 semasleep(-1)
96 i = 0
97 }
98 }
99 }
100 }
101
102 func unlock(l *mutex) {
103 unlockWithRank(l)
104 }
105
106
107
108
109 func unlock2(l *mutex) {
110 gp := getg()
111 var mp *m
112 for {
113 v := atomic.Loaduintptr(&l.key)
114 if v == locked {
115 if atomic.Casuintptr(&l.key, locked, 0) {
116 break
117 }
118 } else {
119
120
121 mp = muintptr(v &^ locked).ptr()
122 if atomic.Casuintptr(&l.key, v, uintptr(mp.nextwaitm)) {
123
124 semawakeup(mp)
125 break
126 }
127 }
128 }
129 gp.m.mLockProfile.recordUnlock(l)
130 gp.m.locks--
131 if gp.m.locks < 0 {
132 throw("runtime·unlock: lock count")
133 }
134 if gp.m.locks == 0 && gp.preempt {
135 gp.stackguard0 = stackPreempt
136 }
137 }
138
139
140 func noteclear(n *note) {
141 n.key = 0
142 }
143
144 func notewakeup(n *note) {
145 var v uintptr
146 for {
147 v = atomic.Loaduintptr(&n.key)
148 if atomic.Casuintptr(&n.key, v, locked) {
149 break
150 }
151 }
152
153
154
155 switch {
156 case v == 0:
157
158 case v == locked:
159
160 throw("notewakeup - double wakeup")
161 default:
162
163 semawakeup((*m)(unsafe.Pointer(v)))
164 }
165 }
166
167 func notesleep(n *note) {
168 gp := getg()
169 if gp != gp.m.g0 {
170 throw("notesleep not on g0")
171 }
172 semacreate(gp.m)
173 if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
174
175 if n.key != locked {
176 throw("notesleep - waitm out of sync")
177 }
178 return
179 }
180
181 gp.m.blocked = true
182 if *cgo_yield == nil {
183 semasleep(-1)
184 } else {
185
186 const ns = 10e6
187 for atomic.Loaduintptr(&n.key) == 0 {
188 semasleep(ns)
189 asmcgocall(*cgo_yield, nil)
190 }
191 }
192 gp.m.blocked = false
193 }
194
195
196 func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
197
198
199
200
201 gp = getg()
202
203
204 if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
205
206 if n.key != locked {
207 throw("notetsleep - waitm out of sync")
208 }
209 return true
210 }
211 if ns < 0 {
212
213 gp.m.blocked = true
214 if *cgo_yield == nil {
215 semasleep(-1)
216 } else {
217
218 const ns = 10e6
219 for semasleep(ns) < 0 {
220 asmcgocall(*cgo_yield, nil)
221 }
222 }
223 gp.m.blocked = false
224 return true
225 }
226
227 deadline = nanotime() + ns
228 for {
229
230 gp.m.blocked = true
231 if *cgo_yield != nil && ns > 10e6 {
232 ns = 10e6
233 }
234 if semasleep(ns) >= 0 {
235 gp.m.blocked = false
236
237
238 return true
239 }
240 if *cgo_yield != nil {
241 asmcgocall(*cgo_yield, nil)
242 }
243 gp.m.blocked = false
244
245 ns = deadline - nanotime()
246 if ns <= 0 {
247 break
248 }
249
250 }
251
252
253
254
255
256 for {
257 v := atomic.Loaduintptr(&n.key)
258 switch v {
259 case uintptr(unsafe.Pointer(gp.m)):
260
261 if atomic.Casuintptr(&n.key, v, 0) {
262 return false
263 }
264 case locked:
265
266
267 gp.m.blocked = true
268 if semasleep(-1) < 0 {
269 throw("runtime: unable to acquire - semaphore out of sync")
270 }
271 gp.m.blocked = false
272 return true
273 default:
274 throw("runtime: unexpected waitm - semaphore out of sync")
275 }
276 }
277 }
278
279 func notetsleep(n *note, ns int64) bool {
280 gp := getg()
281 if gp != gp.m.g0 {
282 throw("notetsleep not on g0")
283 }
284 semacreate(gp.m)
285 return notetsleep_internal(n, ns, nil, 0)
286 }
287
288
289
290 func notetsleepg(n *note, ns int64) bool {
291 gp := getg()
292 if gp == gp.m.g0 {
293 throw("notetsleepg on g0")
294 }
295 semacreate(gp.m)
296 entersyscallblock()
297 ok := notetsleep_internal(n, ns, nil, 0)
298 exitsyscall()
299 return ok
300 }
301
302 func beforeIdle(int64, int64) (*g, bool) {
303 return nil, false
304 }
305
306 func checkTimeouts() {}
307
View as plain text