aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/lock_js.go
diff options
context:
space:
mode:
authorRichard Musiol <mail@richard-musiol.de>2019-10-10 22:38:26 +0200
committerRichard Musiol <neelance@gmail.com>2019-10-11 18:09:33 +0000
commit2686e7494845dae877e0efb4ff786c672b2cd2ef (patch)
treee425983c821567c7c12332293f3664e04b9d6cb1 /src/runtime/lock_js.go
parent426bfbe9a375aebf5df2fbc5eb340fccc0466382 (diff)
downloadgo-2686e7494845dae877e0efb4ff786c672b2cd2ef.tar.gz
go-2686e7494845dae877e0efb4ff786c672b2cd2ef.zip
runtime: make goroutine for wasm async events short-lived
An extra goroutine is necessary to handle asynchronous events on wasm. However, we do not want this goroutine to exist all the time. This change makes it short-lived, so it ends after the asynchronous event was handled. Fixes #34768 Change-Id: I24626ff0af9d803a01ebe33fbb584d04d2059a44 Reviewed-on: https://go-review.googlesource.com/c/go/+/200497 Run-TryBot: Richard Musiol <neelance@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/lock_js.go')
-rw-r--r--src/runtime/lock_js.go45
1 files changed, 26 insertions, 19 deletions
diff --git a/src/runtime/lock_js.go b/src/runtime/lock_js.go
index d08238ce3c..23f17080f2 100644
--- a/src/runtime/lock_js.go
+++ b/src/runtime/lock_js.go
@@ -144,28 +144,19 @@ func checkTimeouts() {
}
}
+var isHandlingEvent = false
+var nextEventIsAsync = false
var returnedEventHandler *g
-func init() {
- // At the toplevel we need an extra goroutine that handles asynchronous events.
- initg := getg()
- go handleAsyncEvents(initg)
- gopark(nil, nil, waitReasonZero, traceEvNone, 1)
-}
-
-func handleAsyncEvents(initg *g) {
- returnedEventHandler = getg()
- goready(initg, 1)
-
- gopark(nil, nil, waitReasonZero, traceEvNone, 1)
- returnedEventHandler = nil
-
- pause(getcallersp() - 16)
-}
-
// beforeIdle gets called by the scheduler if no goroutine is awake.
-// We resume the event handler (if available) which will pause the execution.
+// 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 {
+ if !isHandlingEvent {
+ nextEventIsAsync = true
+ pause(getcallersp() - 16)
+ return true
+ }
if returnedEventHandler != nil {
goready(returnedEventHandler, 1)
return true
@@ -184,20 +175,36 @@ func scheduleTimeoutEvent(ms int64) int32
func clearTimeoutEvent(id int32)
func handleEvent() {
+ if nextEventIsAsync {
+ nextEventIsAsync = false
+ checkTimeouts()
+ go handleAsyncEvent()
+ return
+ }
+
+ prevIsHandlingEvent := isHandlingEvent
+ isHandlingEvent = true
prevReturnedEventHandler := returnedEventHandler
returnedEventHandler = nil
- checkTimeouts()
eventHandler()
+ // wait until all goroutines are idle
returnedEventHandler = getg()
gopark(nil, nil, waitReasonZero, traceEvNone, 1)
+ isHandlingEvent = prevIsHandlingEvent
returnedEventHandler = prevReturnedEventHandler
pause(getcallersp() - 16)
}
+func handleAsyncEvent() {
+ isHandlingEvent = true
+ eventHandler()
+ isHandlingEvent = false
+}
+
var eventHandler func()
//go:linkname setEventHandler syscall/js.setEventHandler