diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 9ae1f982b9..bea2e005ba 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -71,9 +71,9 @@ func panicOrGoexit(message interface{}, panicking panicState) { } } if panicking == panicGoexit { - // Call to Goexit() instead of a panic. + // This is a call to Goexit() instead of a panic. // Exit the goroutine instead of printing a panic message. - deadlock() + exitGoroutine() } printstring("panic: ") printitf(message) diff --git a/src/runtime/scheduler_cooperative.go b/src/runtime/scheduler_cooperative.go index 3cb1e3f987..f5042b6b31 100644 --- a/src/runtime/scheduler_cooperative.go +++ b/src/runtime/scheduler_cooperative.go @@ -45,9 +45,18 @@ var ( // //go:noinline func deadlock() { - // call yield without requesting a wakeup + exitGoroutine() +} + +func exitGoroutine() { + // Pause the goroutine without a way for it to wake up. + // This makes the goroutine unreachable, and should eventually get it + // cleaned up by the GC. task.Pause() - panic("unreachable") + + // We will never return from task.Pause(). Make sure the compiler knows + // this. + trap() } // Add this task to the end of the run queue. diff --git a/src/runtime/scheduler_none.go b/src/runtime/scheduler_none.go index dc4b03b6e2..1c2da7eb0a 100644 --- a/src/runtime/scheduler_none.go +++ b/src/runtime/scheduler_none.go @@ -36,6 +36,12 @@ func deadlock() { runtimePanic("all goroutines are asleep - deadlock!") } +func exitGoroutine() { + // There is only one goroutine, which would exit, so that leads to a + // deadlock. + deadlock() +} + func scheduleTask(t *task.Task) { // Pause() will panic, so this should not be reachable. }