1
0
mirror of https://github.com/golang/go synced 2024-11-26 23:11:24 -07:00

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 <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
This commit is contained in:
Ian Lance Taylor 2019-04-10 17:18:22 -07:00
parent 7c3060e923
commit 10e7bc994f
4 changed files with 31 additions and 4 deletions

View File

@ -230,7 +230,7 @@ func notetsleepg(n *note, ns int64) bool {
return ok
}
func beforeIdle() bool {
func beforeIdle(int64) bool {
return false
}

View File

@ -111,6 +111,8 @@ func notetsleepg(n *note, ns int64) bool {
gopark(nil, nil, waitReasonSleep, traceEvNone, 1)
clearTimeoutEvent(id) // note might have woken early, clear timeout
clearIdleID()
mp = acquirem()
delete(notes, n)
delete(notesWithTimeout, n)
@ -148,10 +150,25 @@ var isHandlingEvent = false
var nextEventIsAsync = false
var returnedEventHandler *g
// The timeout event started by beforeIdle.
var idleID int32
// beforeIdle gets called by the scheduler if no goroutine is awake.
// If we are not already handling an event, then we pause for an async event.
// If an event handler returned, we resume it and it will pause the execution.
func beforeIdle() bool {
func beforeIdle(delay int64) bool {
if delay > 0 {
if delay < 1e6 {
delay = 1
} else if delay < 1e15 {
delay = delay / 1e6
} else {
// An arbitrary cap on how long to wait for a timer.
// 1e9 ms == ~11.5 days.
delay = 1e9
}
idleID = scheduleTimeoutEvent(delay)
}
if !isHandlingEvent {
nextEventIsAsync = true
pause(getcallersp() - 16)
@ -164,6 +181,14 @@ func beforeIdle() bool {
return false
}
// clearIdleID clears our record of the timeout started by beforeIdle.
func clearIdleID() {
if idleID != 0 {
clearTimeoutEvent(idleID)
idleID = 0
}
}
// pause sets SP to newsp and pauses the execution of Go's WebAssembly code until an event is triggered.
func pause(newsp uintptr)
@ -189,6 +214,8 @@ func handleEvent() {
eventHandler()
clearIdleID()
// wait until all goroutines are idle
returnedEventHandler = getg()
gopark(nil, nil, waitReasonZero, traceEvNone, 1)

View File

@ -289,7 +289,7 @@ func notetsleepg(n *note, ns int64) bool {
return ok
}
func beforeIdle() bool {
func beforeIdle(int64) bool {
return false
}

View File

@ -2355,7 +2355,7 @@ stop:
// wasm only:
// If a callback returned and no other goroutine is awake,
// then pause execution until a callback was triggered.
if beforeIdle() {
if beforeIdle(delta) {
// At least one goroutine got woken.
goto top
}