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