Commit e4a95b63 authored by Austin Clements's avatar Austin Clements

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/20035Reviewed-by: 's avatarRick Hudson <rlh@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent d7cedc4b
...@@ -331,6 +331,7 @@ func selecttype(size int32) *Type { ...@@ -331,6 +331,7 @@ func selecttype(size int32) *Type {
sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("ticket")), typenod(Types[TUINT32]))) sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("ticket")), typenod(Types[TUINT32])))
sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8])))) sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8]))))
sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("c")), typenod(Ptrto(Types[TUINT8]))))
typecheck(&sudog, Etype) typecheck(&sudog, Etype)
sudog.Type.Noalg = true sudog.Type.Noalg = true
sudog.Type.Local = true sudog.Type.Local = true
......
...@@ -209,6 +209,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -209,6 +209,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
mysg.waitlink = nil mysg.waitlink = nil
mysg.g = gp mysg.g = gp
mysg.selectdone = nil mysg.selectdone = nil
mysg.c = c
gp.waiting = mysg gp.waiting = mysg
gp.param = nil gp.param = nil
c.sendq.enqueue(mysg) c.sendq.enqueue(mysg)
...@@ -229,6 +230,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -229,6 +230,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
if mysg.releasetime > 0 { if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2) blockevent(mysg.releasetime-t0, 2)
} }
mysg.c = nil
releaseSudog(mysg) releaseSudog(mysg)
return true return true
} }
...@@ -469,6 +471,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r ...@@ -469,6 +471,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
gp.waiting = mysg gp.waiting = mysg
mysg.g = gp mysg.g = gp
mysg.selectdone = nil mysg.selectdone = nil
mysg.c = c
gp.param = nil gp.param = nil
c.recvq.enqueue(mysg) c.recvq.enqueue(mysg)
goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3) goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
...@@ -483,6 +486,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r ...@@ -483,6 +486,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
} }
closed := gp.param == nil closed := gp.param == nil
gp.param = nil gp.param = nil
mysg.c = nil
releaseSudog(mysg) releaseSudog(mysg)
return true, !closed return true, !closed
} }
......
...@@ -329,6 +329,9 @@ func releaseSudog(s *sudog) { ...@@ -329,6 +329,9 @@ func releaseSudog(s *sudog) {
if s.waitlink != nil { if s.waitlink != nil {
throw("runtime: sudog with non-nil waitlink") throw("runtime: sudog with non-nil waitlink")
} }
if s.c != nil {
throw("runtime: sudog with non-nil c")
}
gp := getg() gp := getg()
if gp.param != nil { if gp.param != nil {
throw("runtime: releaseSudog with non-nil gp.param") throw("runtime: releaseSudog with non-nil gp.param")
......
...@@ -215,13 +215,14 @@ type gobuf struct { ...@@ -215,13 +215,14 @@ type gobuf struct {
// selecttype. // selecttype.
type sudog struct { type sudog struct {
g *g g *g
selectdone *uint32 selectdone *uint32 // CAS to 1 to win select race (may point to stack)
next *sudog next *sudog
prev *sudog prev *sudog
elem unsafe.Pointer // data element elem unsafe.Pointer // data element (may point to stack)
releasetime int64 releasetime int64
ticket uint32 ticket uint32
waitlink *sudog // g.waiting list waitlink *sudog // g.waiting list
c *hchan // channel
} }
type gcstats struct { type gcstats struct {
......
...@@ -385,6 +385,7 @@ loop: ...@@ -385,6 +385,7 @@ loop:
sg.releasetime = -1 sg.releasetime = -1
} }
sg.waitlink = gp.waiting sg.waitlink = gp.waiting
sg.c = c
gp.waiting = sg gp.waiting = sg
switch cas.kind { switch cas.kind {
...@@ -416,6 +417,7 @@ loop: ...@@ -416,6 +417,7 @@ loop:
for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
sg1.selectdone = nil sg1.selectdone = nil
sg1.elem = nil sg1.elem = nil
sg1.c = nil
} }
gp.waiting = nil gp.waiting = nil
for i := int(sel.ncase) - 1; i >= 0; i-- { for i := int(sel.ncase) - 1; i >= 0; i-- {
......
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