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 lockWithRank(l, getLockRank(l))
37 }
38
39 func lock2(l *mutex) {
40 gp := getg()
41 if gp.m.locks < 0 {
42 throw("runtime·lock: lock count")
43 }
44 gp.m.locks++
45
46
47 if atomic.Casuintptr(&l.key, 0, locked) {
48 return
49 }
50 semacreate(gp.m)
51
52
53
54 spin := 0
55 if ncpu > 1 {
56 spin = active_spin
57 }
58 Loop:
59 for i := 0; ; i++ {
60 v := atomic.Loaduintptr(&l.key)
61 if v&locked == 0 {
62
63 if atomic.Casuintptr(&l.key, v, v|locked) {
64 return
65 }
66 i = 0
67 }
68 if i < spin {
69 procyield(active_spin_cnt)
70 } else if i < spin+passive_spin {
71 osyield()
72 } else {
73
74
75
76
77 for {
78 gp.m.nextwaitm = muintptr(v &^ locked)
79 if atomic.Casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|locked) {
80 break
81 }
82 v = atomic.Loaduintptr(&l.key)
83 if v&locked == 0 {
84 continue Loop
85 }
86 }
87 if v&locked != 0 {
88
89 semasleep(-1)
90 i = 0
91 }
92 }
93 }
94 }
95
96 func unlock(l *mutex) {
97 unlockWithRank(l)
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