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