mirror of
https://github.com/golang/go
synced 2024-11-18 08:24:44 -07:00
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>
This commit is contained in:
parent
426bfbe9a3
commit
2686e74948
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.)
|
||||
)
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user