]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: record channel in sudog
authorAustin Clements <austin@google.com>
Mon, 15 Feb 2016 22:37:04 +0000 (17:37 -0500)
committerAustin Clements <austin@google.com>
Wed, 16 Mar 2016 20:13:02 +0000 (20:13 +0000)
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>

src/cmd/compile/internal/gc/select.go
src/runtime/chan.go
src/runtime/proc.go
src/runtime/runtime2.go
src/runtime/select.go

index 3ee21b70e8f3145ad7b83b852231845588d3c55c..f4445823b55acdccaf8c166ece0559ac2d9014c9 100644 (file)
@@ -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("ticket")), typenod(Types[TUINT32])))
        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)
        sudog.Type.Noalg = true
        sudog.Type.Local = true
index 85cbe5a5a7f0ac52e6ecc1e8bc66b69a818bce0a..cc64d30a6847f88a7dae5e0f2b88921d60f5e9fa 100644 (file)
@@ -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
 }
index 758a0a898c1d655994dd4711f87c3af1fc023a3e..aea1f0d18cdfc9e26622d73b0f7dd936cf39701a 100644 (file)
@@ -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")
index 3ac8f196c566405f2553fc08b00e82b21d509c0f..ac437def263164ff0bc1ad49a541859181c47769 100644 (file)
@@ -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 {
index ddc3d81638ef6a0b8f5a29e8ea40023a40531b8f..fff8afa9ff8d855927a07ae10ff8c9b021a49392 100644 (file)
@@ -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-- {