diff options
author | Keith Randall <khr@golang.org> | 2014-12-15 14:39:28 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2015-01-14 06:16:34 +0000 |
commit | 97b84fc4c86936ac0b012a7f091f70b1f791c11c (patch) | |
tree | c104e0cb16c2aaf278de99604353c62051f77dbf | |
parent | add1ee0ed5e0ace0a7d09d9aed38cbd7063f5f28 (diff) | |
download | go-97b84fc4c86936ac0b012a7f091f70b1f791c11c.tar.gz go-97b84fc4c86936ac0b012a7f091f70b1f791c11c.zip |
[release-branch.go1.4] runtime: fix deadlock in runtime.Stack
It shouldn't semacquire() inside an acquirem(), the runtime
thinks that means deadlock. It actually isn't a deadlock, but it
looks like it because acquirem() does m.locks++.
Candidate for inclusion in 1.4.1. runtime.Stack with all=true
is pretty unuseable in GOMAXPROCS>1 environment.
fixes #9321
Change-Id: Iac6b664217d24763b9878c20e49229a1ecffc805
Reviewed-on: https://go-review.googlesource.com/1600
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
(cherry picked from commit 50bc3d5bbc6710663c082aa72c8ba4f9ee515ab3)
Reviewed-on: https://go-review.googlesource.com/2807
Reviewed-by: Andrew Gerrand <adg@golang.org>
-rw-r--r-- | src/runtime/mprof.go | 14 | ||||
-rw-r--r-- | test/fixedbugs/issue9321.go | 37 |
2 files changed, 42 insertions, 9 deletions
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index d409c6c306..f4da45f5c3 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -575,20 +575,16 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) { // If all is true, Stack formats stack traces of all other goroutines // into buf after the trace for the current goroutine. func Stack(buf []byte, all bool) int { - mp := acquirem() - gp := mp.curg if all { semacquire(&worldsema, false) - mp.gcing = 1 - releasem(mp) + gp := getg() + gp.m.gcing = 1 onM(stoptheworld) - if mp != acquirem() { - gothrow("Stack: rescheduled") - } } n := 0 if len(buf) > 0 { + gp := getg() sp := getcallersp(unsafe.Pointer(&buf)) pc := getcallerpc(unsafe.Pointer(&buf)) onM(func() { @@ -605,11 +601,11 @@ func Stack(buf []byte, all bool) int { } if all { - mp.gcing = 0 + gp := getg() + gp.m.gcing = 0 semrelease(&worldsema) onM(starttheworld) } - releasem(mp) return n } diff --git a/test/fixedbugs/issue9321.go b/test/fixedbugs/issue9321.go new file mode 100644 index 0000000000..06cb5a6e36 --- /dev/null +++ b/test/fixedbugs/issue9321.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "runtime" + "runtime/pprof" + "sync" +) + +func test() { + var wg sync.WaitGroup + wg.Add(2) + test := func() { + for i := 0; i < 100; i++ { + buf := &bytes.Buffer{} + pprof.Lookup("goroutine").WriteTo(buf, 2) + } + wg.Done() + } + + go test() + go test() + wg.Wait() +} + +func main() { + runtime.GOMAXPROCS(2) + for i := 0; i < 100; i++ { + test() + } +} |