]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.4] runtime: fix deadlock in runtime.Stack
authorKeith Randall <khr@golang.org>
Mon, 15 Dec 2014 22:39:28 +0000 (14:39 -0800)
committerRuss Cox <rsc@golang.org>
Wed, 14 Jan 2015 06:16:34 +0000 (06:16 +0000)
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>
src/runtime/mprof.go
test/fixedbugs/issue9321.go [new file with mode: 0644]

index d409c6c306a3fe9f32ae5a43ceac739b785f0eaf..f4da45f5c307d51894645e6c4623c412b5f04167 100644 (file)
@@ -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 (file)
index 0000000..06cb5a6
--- /dev/null
@@ -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()
+       }
+}