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