]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add wasm support for timers on P's
authorIan Lance Taylor <iant@golang.org>
Thu, 11 Apr 2019 00:18:22 +0000 (17:18 -0700)
committerIan Lance Taylor <iant@golang.org>
Mon, 21 Oct 2019 21:43:41 +0000 (21:43 +0000)
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>
src/runtime/lock_futex.go
src/runtime/lock_js.go
src/runtime/lock_sema.go
src/runtime/proc.go

index d2828b138ab21c1e467781384379d22e7f30fa28..92873f2daca203c03133b266c2a175017f723fac 100644 (file)
@@ -230,7 +230,7 @@ func notetsleepg(n *note, ns int64) bool {
        return ok
 }
 
-func beforeIdle() bool {
+func beforeIdle(int64) bool {
        return false
 }
 
index 23f17080f26f18ca4ec3376c79e34befc022e787..51cbe606071562bd328ac7644614aa81fea043fd 100644 (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)
index 9507d46f41c58c465400960d402de6524e939526..af9517d74405ad631fc85fe71a6c79766d0bddf4 100644 (file)
@@ -289,7 +289,7 @@ func notetsleepg(n *note, ns int64) bool {
        return ok
 }
 
-func beforeIdle() bool {
+func beforeIdle(int64) bool {
        return false
 }
 
index 71e756b991c1e73b09ea63c89cca8019a36ea96a..fd93a3db5fcc5a6876f41e63ba94a29289356f31 100644 (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
        }