]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make goroutine for wasm async events short-lived
authorRichard Musiol <mail@richard-musiol.de>
Thu, 10 Oct 2019 20:38:26 +0000 (22:38 +0200)
committerRichard Musiol <neelance@gmail.com>
Fri, 11 Oct 2019 18:09:33 +0000 (18:09 +0000)
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>
src/cmd/internal/objabi/funcid.go
src/runtime/lock_js.go
src/runtime/symtab.go
src/runtime/traceback.go

index fe54eba663183e3c03d5019c4e938faa12a5bc60..c13c3cb45894d5595fe5efce5c4f9592cf0bd8b7 100644 (file)
@@ -37,7 +37,7 @@ const (
        FuncID_debugCallV1
        FuncID_gopanic
        FuncID_panicwrap
-       FuncID_handleAsyncEvents
+       FuncID_handleAsyncEvent
        FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
 )
 
@@ -83,8 +83,8 @@ func GetFuncID(name, file string) FuncID {
                return FuncID_gopanic
        case "runtime.panicwrap":
                return FuncID_panicwrap
-       case "runtime.handleAsyncEvents":
-               return FuncID_handleAsyncEvents
+       case "runtime.handleAsyncEvent":
+               return FuncID_handleAsyncEvent
        }
        if file == "<autogenerated>" {
                return FuncID_wrapper
index d08238ce3cf4f853b82bf412ccc13cd9bd15a1b4..23f17080f26f18ca4ec3376c79e34befc022e787 100644 (file)
@@ -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
index 8296a8590dbb827cc39f98a0cf94b9168327f07e..df6e02f62ad77fe51237f588d68971148dfa699e 100644 (file)
@@ -253,7 +253,7 @@ const (
        funcID_debugCallV1
        funcID_gopanic
        funcID_panicwrap
-       funcID_handleAsyncEvents
+       funcID_handleAsyncEvent
        funcID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
 )
 
index 96fb33c04b2e09e66181e02a105f38ae8f4defae..0e4b75a7e61e81d4315ff8bff65f281cd83c3a8e 100644 (file)
@@ -998,7 +998,7 @@ func topofstack(f funcInfo, g0 bool) bool {
 // isSystemGoroutine reports whether the goroutine g must be omitted
 // in stack dumps and deadlock detector. This is any goroutine that
 // starts at a runtime.* entry point, except for runtime.main,
-// runtime.handleAsyncEvents (wasm only) and sometimes runtime.runfinq.
+// runtime.handleAsyncEvent (wasm only) and sometimes runtime.runfinq.
 //
 // If fixed is true, any goroutine that can vary between user and
 // system (that is, the finalizer goroutine) is considered a user
@@ -1009,7 +1009,7 @@ func isSystemGoroutine(gp *g, fixed bool) bool {
        if !f.valid() {
                return false
        }
-       if f.funcID == funcID_runtime_main || f.funcID == funcID_handleAsyncEvents {
+       if f.funcID == funcID_runtime_main || f.funcID == funcID_handleAsyncEvent {
                return false
        }
        if f.funcID == funcID_runfinq {