Source file
src/runtime/lock_js.go
1
2
3
4
5
6
7 package runtime
8
9 import _ "unsafe"
10
11
12
13 const (
14 mutex_unlocked = 0
15 mutex_locked = 1
16
17 note_cleared = 0
18 note_woken = 1
19 note_timeout = 2
20
21 active_spin = 4
22 active_spin_cnt = 30
23 passive_spin = 1
24 )
25
26 func lock(l *mutex) {
27 lockWithRank(l, getLockRank(l))
28 }
29
30 func lock2(l *mutex) {
31 if l.key == mutex_locked {
32
33
34 throw("self deadlock")
35 }
36 gp := getg()
37 if gp.m.locks < 0 {
38 throw("lock count")
39 }
40 gp.m.locks++
41 l.key = mutex_locked
42 }
43
44 func unlock(l *mutex) {
45 unlockWithRank(l)
46 }
47
48 func unlock2(l *mutex) {
49 if l.key == mutex_unlocked {
50 throw("unlock of unlocked lock")
51 }
52 gp := getg()
53 gp.m.locks--
54 if gp.m.locks < 0 {
55 throw("lock count")
56 }
57 l.key = mutex_unlocked
58 }
59
60
61
62 type noteWithTimeout struct {
63 gp *g
64 deadline int64
65 }
66
67 var (
68 notes = make(map[*note]*g)
69 notesWithTimeout = make(map[*note]noteWithTimeout)
70 )
71
72 func noteclear(n *note) {
73 n.key = note_cleared
74 }
75
76 func notewakeup(n *note) {
77
78 if n.key == note_woken {
79 throw("notewakeup - double wakeup")
80 }
81 cleared := n.key == note_cleared
82 n.key = note_woken
83 if cleared {
84 goready(notes[n], 1)
85 }
86 }
87
88 func notesleep(n *note) {
89 throw("notesleep not supported by js")
90 }
91
92 func notetsleep(n *note, ns int64) bool {
93 throw("notetsleep not supported by js")
94 return false
95 }
96
97
98 func notetsleepg(n *note, ns int64) bool {
99 gp := getg()
100 if gp == gp.m.g0 {
101 throw("notetsleepg on g0")
102 }
103
104 if ns >= 0 {
105 deadline := nanotime() + ns
106 delay := ns/1000000 + 1
107 if delay > 1<<31-1 {
108 delay = 1<<31 - 1
109 }
110
111 id := scheduleTimeoutEvent(delay)
112 mp := acquirem()
113 notes[n] = gp
114 notesWithTimeout[n] = noteWithTimeout{gp: gp, deadline: deadline}
115 releasem(mp)
116
117 gopark(nil, nil, waitReasonSleep, traceBlockSleep, 1)
118
119 clearTimeoutEvent(id)
120
121 mp = acquirem()
122 delete(notes, n)
123 delete(notesWithTimeout, n)
124 releasem(mp)
125
126 return n.key == note_woken
127 }
128
129 for n.key != note_woken {
130 mp := acquirem()
131 notes[n] = gp
132 releasem(mp)
133
134 gopark(nil, nil, waitReasonZero, traceBlockGeneric, 1)
135
136 mp = acquirem()
137 delete(notes, n)
138 releasem(mp)
139 }
140 return true
141 }
142
143
144
145
146
147 func checkTimeouts() {
148 now := nanotime()
149
150 for n, nt := range notesWithTimeout {
151 if n.key == note_cleared && now >= nt.deadline {
152 n.key = note_timeout
153 goready(nt.gp, 1)
154 }
155 }
156 }
157
158
159 var events []*event
160
161 type event struct {
162
163
164 gp *g
165
166
167
168 returned bool
169 }
170
171 type timeoutEvent struct {
172 id int32
173
174 time int64
175 }
176
177
178 func (e *timeoutEvent) diff(x int64) int64 {
179 if e == nil {
180 return 0
181 }
182
183 diff := x - idleTimeout.time
184 if diff < 0 {
185 diff = -diff
186 }
187 return diff
188 }
189
190
191 func (e *timeoutEvent) clear() {
192 if e == nil {
193 return
194 }
195
196 clearTimeoutEvent(e.id)
197 }
198
199
200 var idleTimeout *timeoutEvent
201
202
203
204
205
206
207
208
209
210 func beforeIdle(now, pollUntil int64) (gp *g, otherReady bool) {
211 delay := int64(-1)
212 if pollUntil != 0 {
213
214 delay = (pollUntil-now-1)/1e6 + 1
215 if delay > 1e9 {
216
217
218 delay = 1e9
219 }
220 }
221
222 if delay > 0 && (idleTimeout == nil || idleTimeout.diff(pollUntil) > 1e6) {
223
224 idleTimeout.clear()
225
226 idleTimeout = &timeoutEvent{
227 id: scheduleTimeoutEvent(delay),
228 time: pollUntil,
229 }
230 }
231
232 if len(events) == 0 {
233
234 go handleAsyncEvent()
235 return nil, true
236 }
237
238 e := events[len(events)-1]
239 if e.returned {
240 return e.gp, false
241 }
242 return nil, false
243 }
244
245 var idleStart int64
246
247 func handleAsyncEvent() {
248 idleStart = nanotime()
249 pause(getcallersp() - 16)
250 }
251
252
253 func clearIdleTimeout() {
254 idleTimeout.clear()
255 idleTimeout = nil
256 }
257
258
259 func pause(newsp uintptr)
260
261
262
263
264
265 func scheduleTimeoutEvent(ms int64) int32
266
267
268
269
270 func clearTimeoutEvent(id int32)
271
272
273
274
275
276 func handleEvent() {
277 sched.idleTime.Add(nanotime() - idleStart)
278
279 e := &event{
280 gp: getg(),
281 returned: false,
282 }
283 events = append(events, e)
284
285 if !eventHandler() {
286
287 clearIdleTimeout()
288 }
289
290
291 e.returned = true
292 gopark(nil, nil, waitReasonZero, traceBlockGeneric, 1)
293
294 events[len(events)-1] = nil
295 events = events[:len(events)-1]
296
297
298 idleStart = nanotime()
299 pause(getcallersp() - 16)
300 }
301
302
303
304 var eventHandler func() bool
305
306
307 func setEventHandler(fn func() bool) {
308 eventHandler = fn
309 }
310
View as plain text