aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/runtime/crash_test.go34
-rw-r--r--src/runtime/heapdump.go2
-rw-r--r--src/runtime/mfinal.go9
-rw-r--r--src/runtime/mgc0.go2
-rw-r--r--src/runtime/proc.go1
-rw-r--r--src/runtime/proc1.go2
-rw-r--r--src/runtime/runtime2.go1
-rw-r--r--src/runtime/time.go1
-rw-r--r--src/runtime/traceback.go23
9 files changed, 61 insertions, 14 deletions
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 43cea9008a..715b2da232 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
"strings"
"sync"
@@ -17,17 +18,20 @@ import (
"text/template"
)
-// testEnv excludes GODEBUG from the environment
-// to prevent its output from breaking tests that
-// are trying to parse other command output.
func testEnv(cmd *exec.Cmd) *exec.Cmd {
if cmd.Env != nil {
panic("environment already set")
}
for _, env := range os.Environ() {
+ // Exclude GODEBUG from the environment to prevent its output
+ // from breaking tests that are trying to parse other command output.
if strings.HasPrefix(env, "GODEBUG=") {
continue
}
+ // Exclude GOTRACEBACK for the same reason.
+ if strings.HasPrefix(env, "GOTRACEBACK=") {
+ continue
+ }
cmd.Env = append(cmd.Env, env)
}
return cmd
@@ -217,6 +221,14 @@ func TestMainGoroutineId(t *testing.T) {
}
}
+func TestNoHelperGoroutines(t *testing.T) {
+ output := executeTest(t, noHelperGoroutinesSource, nil)
+ matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
+ if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
+ t.Fatalf("want to see only goroutine 1, see:\n%s", output)
+ }
+}
+
func TestBreakpoint(t *testing.T) {
output := executeTest(t, breakpointSource, nil)
want := "runtime.Breakpoint()"
@@ -431,6 +443,22 @@ func main() {
}
`
+const noHelperGoroutinesSource = `
+package main
+import (
+ "runtime"
+ "time"
+)
+func init() {
+ i := 0
+ runtime.SetFinalizer(&i, func(p *int) {})
+ time.AfterFunc(time.Hour, func() {})
+ panic("oops")
+}
+func main() {
+}
+`
+
const breakpointSource = `
package main
import "runtime"
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index 6cbb5f3775..7b4a846195 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -344,7 +344,7 @@ func dumpgoroutine(gp *g) {
dumpint(uint64(gp.goid))
dumpint(uint64(gp.gopc))
dumpint(uint64(readgstatus(gp)))
- dumpbool(gp.issystem)
+ dumpbool(isSystemGoroutine(gp))
dumpbool(false) // isbackground
dumpint(uint64(gp.waitsince))
dumpstr(gp.waitreason)
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 28afa0dfab..525aa0955a 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -102,7 +102,10 @@ func wakefing() *g {
return res
}
-var fingCreate uint32
+var (
+ fingCreate uint32
+ fingRunning bool
+)
func createfing() {
// start the finalizer goroutine exactly once
@@ -126,9 +129,7 @@ func runfinq() {
gp := getg()
fing = gp
fingwait = true
- gp.issystem = true
goparkunlock(&finlock, "finalizer wait", traceEvGoBlock)
- gp.issystem = false
continue
}
unlock(&finlock)
@@ -169,7 +170,9 @@ func runfinq() {
default:
throw("bad kind in runfinq")
}
+ fingRunning = true
reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
+ fingRunning = false
// drop finalizer queue references to finalized object
f.fn = nil
diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go
index bbd786d519..f54d93377d 100644
--- a/src/runtime/mgc0.go
+++ b/src/runtime/mgc0.go
@@ -62,7 +62,6 @@ func clearpools() {
// bggc holds the state of the backgroundgc.
func backgroundgc() {
bggc.g = getg()
- bggc.g.issystem = true
for {
gcwork(0)
lock(&bggc.lock)
@@ -73,7 +72,6 @@ func backgroundgc() {
func bgsweep() {
sweep.g = getg()
- getg().issystem = true
for {
for gosweepone() != ^uintptr(0) {
sweep.nbgsweep++
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index c8f6de1ac8..0411d965a4 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -110,7 +110,6 @@ func init() {
func forcegchelper() {
forcegc.g = getg()
- forcegc.g.issystem = true
for {
lock(&forcegc.lock)
if forcegc.idle != 0 {
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 70addbffad..1f3ae500fc 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -2636,7 +2636,7 @@ func checkdead() {
lock(&allglock)
for i := 0; i < len(allgs); i++ {
gp := allgs[i]
- if gp.issystem {
+ if isSystemGoroutine(gp) {
continue
}
s := readgstatus(gp)
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index e38d11a59d..fab2ccbebf 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -199,7 +199,6 @@ type g struct {
waitsince int64 // approx time when the g become blocked
waitreason string // if status==gwaiting
schedlink *g
- issystem bool // do not output in stack dump, ignore in deadlock detector
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
paniconfault bool // panic (instead of crash) on unexpected fault address
preemptscan bool // preempted g does scan for gc
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 50895ca8ec..6a2cc2136c 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -153,7 +153,6 @@ func deltimer(t *timer) bool {
// If addtimer inserts a new earlier event, addtimer1 wakes timerproc early.
func timerproc() {
timers.gp = getg()
- timers.gp.issystem = true
for {
lock(&timers.lock)
timers.sleeping = false
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 6c87d7e2e4..8c31c5abad 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -39,6 +39,11 @@ var (
mstartPC uintptr
rt0_goPC uintptr
sigpanicPC uintptr
+ runfinqPC uintptr
+ backgroundgcPC uintptr
+ bgsweepPC uintptr
+ forcegchelperPC uintptr
+ timerprocPC uintptr
systemstack_switchPC uintptr
externalthreadhandlerp uintptr // initialized elsewhere
@@ -56,6 +61,11 @@ func tracebackinit() {
mstartPC = funcPC(mstart)
rt0_goPC = funcPC(rt0_go)
sigpanicPC = funcPC(sigpanic)
+ runfinqPC = funcPC(runfinq)
+ backgroundgcPC = funcPC(backgroundgc)
+ bgsweepPC = funcPC(bgsweep)
+ forcegchelperPC = funcPC(forcegchelper)
+ timerprocPC = funcPC(timerproc)
systemstack_switchPC = funcPC(systemstack_switch)
}
@@ -606,7 +616,7 @@ func tracebackothers(me *g) {
lock(&allglock)
for _, gp := range allgs {
- if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || gp.issystem && level < 2 {
+ if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
continue
}
print("\n")
@@ -631,3 +641,14 @@ func topofstack(f *_func) bool {
pc == rt0_goPC ||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp
}
+
+// isSystemGoroutine returns true if the goroutine g must be omitted in
+// stack dumps and deadlock detector.
+func isSystemGoroutine(gp *g) bool {
+ pc := gp.startpc
+ return pc == runfinqPC && !fingRunning ||
+ pc == backgroundgcPC ||
+ pc == bgsweepPC ||
+ pc == forcegchelperPC ||
+ pc == timerprocPC
+}