Commit 313fd1cb authored by Russ Cox's avatar Russ Cox

runtime: fix crash in GoroutineProfile

It was just completely broken if you gave it the number
of records it asked for. Make it impossible for that particular
inconsistency to happen again.

Also make it exclude system goroutines, to match both
NumGoroutine and Stack.

Fixes #14046.

Change-Id: Ic238c6b89934ba7b47cccd3440dd347ed11e4c3d
Reviewed-on: https://go-review.googlesource.com/18976
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: 's avatarAustin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 4ec2fd3e
...@@ -522,34 +522,46 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) { ...@@ -522,34 +522,46 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
// Most clients should use the runtime/pprof package instead // Most clients should use the runtime/pprof package instead
// of calling GoroutineProfile directly. // of calling GoroutineProfile directly.
func GoroutineProfile(p []StackRecord) (n int, ok bool) { func GoroutineProfile(p []StackRecord) (n int, ok bool) {
gp := getg()
isOK := func(gp1 *g) bool {
// Checking isSystemGoroutine here makes GoroutineProfile
// consistent with both NumGoroutine and Stack.
return gp1 != gp && readgstatus(gp1) != _Gdead && !isSystemGoroutine(gp1)
}
stopTheWorld("profile")
n = 1
for _, gp1 := range allgs {
if isOK(gp1) {
n++
}
}
n = NumGoroutine()
if n <= len(p) { if n <= len(p) {
gp := getg() ok = true
stopTheWorld("profile") r := p
n = NumGoroutine() // Save current goroutine.
if n <= len(p) { sp := getcallersp(unsafe.Pointer(&p))
ok = true pc := getcallerpc(unsafe.Pointer(&p))
r := p systemstack(func() {
sp := getcallersp(unsafe.Pointer(&p)) saveg(pc, sp, gp, &r[0])
pc := getcallerpc(unsafe.Pointer(&p)) })
systemstack(func() { r = r[1:]
saveg(pc, sp, gp, &r[0])
}) // Save other goroutines.
r = r[1:] for _, gp1 := range allgs {
for _, gp1 := range allgs { if isOK(gp1) {
if gp1 == gp || readgstatus(gp1) == _Gdead {
continue
}
saveg(^uintptr(0), ^uintptr(0), gp1, &r[0]) saveg(^uintptr(0), ^uintptr(0), gp1, &r[0])
r = r[1:] r = r[1:]
} }
} }
startTheWorld()
} }
startTheWorld()
return n, ok return n, ok
} }
......
...@@ -308,3 +308,15 @@ func TestAppendSliceGrowth(t *testing.T) { ...@@ -308,3 +308,15 @@ func TestAppendSliceGrowth(t *testing.T) {
} }
} }
} }
func TestGoroutineProfileTrivial(t *testing.T) {
n1, ok := GoroutineProfile(nil) // should fail, there's at least 1 goroutine
if n1 < 1 || ok {
t.Fatalf("GoroutineProfile(nil) = %d, %v, want >0, false", n1, ok)
}
n2, ok := GoroutineProfile(make([]StackRecord, n1))
if n2 != n1 || !ok {
t.Fatalf("GoroutineProfile(%d) = %d, %v, want %d, true", n1, n2, ok, n1)
}
}
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