aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/lock_futex.go2
-rw-r--r--src/runtime/lock_js.go29
-rw-r--r--src/runtime/lock_sema.go2
-rw-r--r--src/runtime/proc.go2
4 files changed, 31 insertions, 4 deletions
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index d2828b138a..92873f2dac 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -230,7 +230,7 @@ func notetsleepg(n *note, ns int64) bool {
return ok
}
-func beforeIdle() bool {
+func beforeIdle(int64) bool {
return false
}
diff --git a/src/runtime/lock_js.go b/src/runtime/lock_js.go
index 23f17080f2..51cbe60607 100644
--- a/src/runtime/lock_js.go
+++ b/src/runtime/lock_js.go
@@ -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)
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index 9507d46f41..af9517d744 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -289,7 +289,7 @@ func notetsleepg(n *note, ns int64) bool {
return ok
}
-func beforeIdle() bool {
+func beforeIdle(int64) bool {
return false
}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 71e756b991..fd93a3db5f 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -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
}