Skip to content

Commit 10e7bc9

Browse files
runtime: add wasm support for timers on P's
When we put timers on P's, the wasm code will not be able to rely on the timer goroutine. Use the beforeIdle hook to schedule a wakeup. Updates #6239 Updates #27707 Change-Id: Idf6309944778b8c3d7178f5d09431940843ea233 Reviewed-on: https://go-review.googlesource.com/c/go/+/171827 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]>
1 parent 7c3060e commit 10e7bc9

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

src/runtime/lock_futex.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ func notetsleepg(n *note, ns int64) bool {
230230
return ok
231231
}
232232

233-
func beforeIdle() bool {
233+
func beforeIdle(int64) bool {
234234
return false
235235
}
236236

src/runtime/lock_js.go

+28-1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ func notetsleepg(n *note, ns int64) bool {
111111
gopark(nil, nil, waitReasonSleep, traceEvNone, 1)
112112

113113
clearTimeoutEvent(id) // note might have woken early, clear timeout
114+
clearIdleID()
115+
114116
mp = acquirem()
115117
delete(notes, n)
116118
delete(notesWithTimeout, n)
@@ -148,10 +150,25 @@ var isHandlingEvent = false
148150
var nextEventIsAsync = false
149151
var returnedEventHandler *g
150152

153+
// The timeout event started by beforeIdle.
154+
var idleID int32
155+
151156
// beforeIdle gets called by the scheduler if no goroutine is awake.
152157
// If we are not already handling an event, then we pause for an async event.
153158
// If an event handler returned, we resume it and it will pause the execution.
154-
func beforeIdle() bool {
159+
func beforeIdle(delay int64) bool {
160+
if delay > 0 {
161+
if delay < 1e6 {
162+
delay = 1
163+
} else if delay < 1e15 {
164+
delay = delay / 1e6
165+
} else {
166+
// An arbitrary cap on how long to wait for a timer.
167+
// 1e9 ms == ~11.5 days.
168+
delay = 1e9
169+
}
170+
idleID = scheduleTimeoutEvent(delay)
171+
}
155172
if !isHandlingEvent {
156173
nextEventIsAsync = true
157174
pause(getcallersp() - 16)
@@ -164,6 +181,14 @@ func beforeIdle() bool {
164181
return false
165182
}
166183

184+
// clearIdleID clears our record of the timeout started by beforeIdle.
185+
func clearIdleID() {
186+
if idleID != 0 {
187+
clearTimeoutEvent(idleID)
188+
idleID = 0
189+
}
190+
}
191+
167192
// pause sets SP to newsp and pauses the execution of Go's WebAssembly code until an event is triggered.
168193
func pause(newsp uintptr)
169194

@@ -189,6 +214,8 @@ func handleEvent() {
189214

190215
eventHandler()
191216

217+
clearIdleID()
218+
192219
// wait until all goroutines are idle
193220
returnedEventHandler = getg()
194221
gopark(nil, nil, waitReasonZero, traceEvNone, 1)

src/runtime/lock_sema.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ func notetsleepg(n *note, ns int64) bool {
289289
return ok
290290
}
291291

292-
func beforeIdle() bool {
292+
func beforeIdle(int64) bool {
293293
return false
294294
}
295295

src/runtime/proc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2355,7 +2355,7 @@ stop:
23552355
// wasm only:
23562356
// If a callback returned and no other goroutine is awake,
23572357
// then pause execution until a callback was triggered.
2358-
if beforeIdle() {
2358+
if beforeIdle(delta) {
23592359
// At least one goroutine got woken.
23602360
goto top
23612361
}

0 commit comments

Comments
 (0)