aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2016-02-15 17:37:04 -0500
committerAustin Clements <austin@google.com>2016-03-16 20:13:02 +0000
commite4a95b63433cc95c81782713b917b2941e48cb39 (patch)
treec75e4309ada98df7b4a5bd9e2d177983cc417c1f /src/runtime
parentd7cedc4b74f902a3a1b429fb27f85380f6955a6f (diff)
downloadgo-e4a95b63433cc95c81782713b917b2941e48cb39.tar.xz
runtime: record channel in sudog
Given a G, there's currently no way to find the channel it's blocking on. We'll need this information to fix a (probably theoretical) bug in select and to implement concurrent stack shrinking, so record the channel in the sudog. For #12967. Change-Id: If8fb63a140f1d07175818824d08c0ebeec2bdf66 Reviewed-on: https://go-review.googlesource.com/20035 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/chan.go4
-rw-r--r--src/runtime/proc.go3
-rw-r--r--src/runtime/runtime2.go5
-rw-r--r--src/runtime/select.go2
4 files changed, 12 insertions, 2 deletions
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 85cbe5a5a7..cc64d30a68 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -209,6 +209,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
mysg.waitlink = nil
mysg.g = gp
mysg.selectdone = nil
+ mysg.c = c
gp.waiting = mysg
gp.param = nil
c.sendq.enqueue(mysg)
@@ -229,6 +230,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
+ mysg.c = nil
releaseSudog(mysg)
return true
}
@@ -469,6 +471,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
gp.waiting = mysg
mysg.g = gp
mysg.selectdone = nil
+ mysg.c = c
gp.param = nil
c.recvq.enqueue(mysg)
goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
@@ -483,6 +486,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
}
closed := gp.param == nil
gp.param = nil
+ mysg.c = nil
releaseSudog(mysg)
return true, !closed
}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 758a0a898c..aea1f0d18c 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -329,6 +329,9 @@ func releaseSudog(s *sudog) {
if s.waitlink != nil {
throw("runtime: sudog with non-nil waitlink")
}
+ if s.c != nil {
+ throw("runtime: sudog with non-nil c")
+ }
gp := getg()
if gp.param != nil {
throw("runtime: releaseSudog with non-nil gp.param")
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 3ac8f196c5..ac437def26 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -215,13 +215,14 @@ type gobuf struct {
// selecttype.
type sudog struct {
g *g
- selectdone *uint32
+ selectdone *uint32 // CAS to 1 to win select race (may point to stack)
next *sudog
prev *sudog
- elem unsafe.Pointer // data element
+ elem unsafe.Pointer // data element (may point to stack)
releasetime int64
ticket uint32
waitlink *sudog // g.waiting list
+ c *hchan // channel
}
type gcstats struct {
diff --git a/src/runtime/select.go b/src/runtime/select.go
index ddc3d81638..fff8afa9ff 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -385,6 +385,7 @@ loop:
sg.releasetime = -1
}
sg.waitlink = gp.waiting
+ sg.c = c
gp.waiting = sg
switch cas.kind {
@@ -416,6 +417,7 @@ loop:
for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
sg1.selectdone = nil
sg1.elem = nil
+ sg1.c = nil
}
gp.waiting = nil
for i := int(sel.ncase) - 1; i >= 0; i-- {