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