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