diff --git a/src/runtime/panic.go b/src/runtime/panic.go index ec33a4469c..e99fbcbb8f 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 5c4dfd5bf5..9c1054ddd4 100644 --- a/src/runtime/scheduler_cooperative.go +++ b/src/runtime/scheduler_cooperative.go @@ -37,9 +37,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 7775b360eb..b03d572a9f 100644 --- a/src/runtime/scheduler_none.go +++ b/src/runtime/scheduler_none.go @@ -29,6 +29,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. }