diff options
author | Richard Musiol <mail@richard-musiol.de> | 2019-10-10 22:38:26 +0200 |
---|---|---|
committer | Richard Musiol <neelance@gmail.com> | 2019-10-11 18:09:33 +0000 |
commit | 2686e7494845dae877e0efb4ff786c672b2cd2ef (patch) | |
tree | e425983c821567c7c12332293f3664e04b9d6cb1 /src/runtime/lock_js.go | |
parent | 426bfbe9a375aebf5df2fbc5eb340fccc0466382 (diff) | |
download | go-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.go | 45 |
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 |