Commit 55e0f36f authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: fix program termination when main goroutine calls Goexit

Do not consider idle finalizer/bgsweep/timer goroutines as doing something useful.
We can't simply set isbackground for the whole lifetime of the goroutines,
because when finalizer goroutine calls user function, we do want to consider it
as doing something useful.
This is borken due to timers for quite some time.
With background sweep is become even more broken.
Fixes #7784.

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/87960044
parent d826b2ed
...@@ -144,6 +144,15 @@ panic: again ...@@ -144,6 +144,15 @@ panic: again
} }
func TestGoexitExit(t *testing.T) {
output := executeTest(t, goexitExitSource, nil)
want := ""
if output != want {
t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
}
}
const crashSource = ` const crashSource = `
package main package main
...@@ -310,3 +319,22 @@ func main() { ...@@ -310,3 +319,22 @@ func main() {
panic("again") panic("again")
} }
` `
const goexitExitSource = `
package main
import (
"runtime"
"time"
)
func main() {
go func() {
time.Sleep(time.Millisecond)
}()
i := 0
runtime.SetFinalizer(&i, func(p *int) {})
runtime.GC()
runtime.Goexit()
}
`
...@@ -1973,7 +1973,9 @@ bgsweep(void) ...@@ -1973,7 +1973,9 @@ bgsweep(void)
continue; continue;
} }
sweep.parked = true; sweep.parked = true;
g->isbackground = true;
runtime·parkunlock(&gclock, "GC sweep wait"); runtime·parkunlock(&gclock, "GC sweep wait");
g->isbackground = false;
} }
} }
...@@ -2618,7 +2620,9 @@ runfinq(void) ...@@ -2618,7 +2620,9 @@ runfinq(void)
finq = nil; finq = nil;
if(fb == nil) { if(fb == nil) {
runtime·fingwait = true; runtime·fingwait = true;
g->isbackground = true;
runtime·parkunlock(&finlock, "finalizer wait"); runtime·parkunlock(&finlock, "finalizer wait");
g->isbackground = false;
continue; continue;
} }
runtime·unlock(&finlock); runtime·unlock(&finlock);
......
...@@ -238,7 +238,9 @@ timerproc(void) ...@@ -238,7 +238,9 @@ timerproc(void)
if(delta < 0) { if(delta < 0) {
// No timers left - put goroutine to sleep. // No timers left - put goroutine to sleep.
timers.rescheduling = true; timers.rescheduling = true;
g->isbackground = true;
runtime·parkunlock(&timers, "timer goroutine (idle)"); runtime·parkunlock(&timers, "timer goroutine (idle)");
g->isbackground = false;
continue; continue;
} }
// At least one timer pending. Sleep until then. // At least one timer pending. Sleep until then.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment