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