runtime: do not omit stack trace of goroutine that handles async events

On wasm there is a special goroutine that handles asynchronous events.
Blocking this goroutine often causes a deadlock. However, the stack
trace of this goroutine was omitted when printing the deadlock error.

This change adds an exception so the goroutine is not considered as
an internal system goroutine and the stack trace gets printed, which
helps with debugging the deadlock.

Updates #32764

Change-Id: Icc8f5ba3ca5a485d557b7bdd76bf2f1ffb92eb3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/199537
Run-TryBot: Richard Musiol <neelance@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go
index a30bc3f..fe54eba 100644
--- a/src/cmd/internal/objabi/funcid.go
+++ b/src/cmd/internal/objabi/funcid.go
@@ -37,6 +37,7 @@
 	FuncID_debugCallV1
 	FuncID_gopanic
 	FuncID_panicwrap
+	FuncID_handleAsyncEvents
 	FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
 )
 
@@ -82,6 +83,8 @@
 		return FuncID_gopanic
 	case "runtime.panicwrap":
 		return FuncID_panicwrap
+	case "runtime.handleAsyncEvents":
+		return FuncID_handleAsyncEvents
 	}
 	if file == "<autogenerated>" {
 		return FuncID_wrapper
diff --git a/src/runtime/lock_js.go b/src/runtime/lock_js.go
index c038499..d08238c 100644
--- a/src/runtime/lock_js.go
+++ b/src/runtime/lock_js.go
@@ -149,18 +149,20 @@
 func init() {
 	// At the toplevel we need an extra goroutine that handles asynchronous events.
 	initg := getg()
-	go func() {
-		returnedEventHandler = getg()
-		goready(initg, 1)
-
-		gopark(nil, nil, waitReasonZero, traceEvNone, 1)
-		returnedEventHandler = nil
-
-		pause(getcallersp() - 16)
-	}()
+	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.
 func beforeIdle() bool {
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 367e060..8296a85 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -253,6 +253,7 @@
 	funcID_debugCallV1
 	funcID_gopanic
 	funcID_panicwrap
+	funcID_handleAsyncEvents
 	funcID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
 )
 
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index ef48c9f..5153390 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -997,8 +997,8 @@
 
 // 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 and
-// sometimes runtime.runfinq.
+// starts at a runtime.* entry point, except for runtime.main,
+// runtime.handleAsyncEvents (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 @@
 	if !f.valid() {
 		return false
 	}
-	if f.funcID == funcID_runtime_main {
+	if f.funcID == funcID_runtime_main || f.funcID == funcID_handleAsyncEvents {
 		return false
 	}
 	if f.funcID == funcID_runfinq {