Commit 005140a7 authored by Austin Clements's avatar Austin Clements

runtime: put g.waiting list in lock order

Currently the g.waiting list created by a select is in poll order.
However, nothing depends on this, and we're going to need access to
the channel lock order in other places shortly, so modify select to
put the waiting list in channel lock order.

For #12967.

Change-Id: If0d38816216ecbb37a36624d9b25dd96e0a775ec
Reviewed-on: https://go-review.googlesource.com/20037Reviewed-by: 's avatarRick Hudson <rlh@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
parent 26594c3d
...@@ -314,7 +314,7 @@ type g struct { ...@@ -314,7 +314,7 @@ type g struct {
gopc uintptr // pc of go statement that created this goroutine gopc uintptr // pc of go statement that created this goroutine
startpc uintptr // pc of goroutine function startpc uintptr // pc of goroutine function
racectx uintptr racectx uintptr
waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr) waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
// Per-G gcController state // Per-G gcController state
......
...@@ -319,6 +319,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) { ...@@ -319,6 +319,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
sglist *sudog sglist *sudog
sgnext *sudog sgnext *sudog
qp unsafe.Pointer qp unsafe.Pointer
nextp **sudog
) )
loop: loop:
...@@ -374,8 +375,9 @@ loop: ...@@ -374,8 +375,9 @@ loop:
if gp.waiting != nil { if gp.waiting != nil {
throw("gp.waiting != nil") throw("gp.waiting != nil")
} }
for i := 0; i < int(sel.ncase); i++ { nextp = &gp.waiting
cas = &scases[pollorder[i]] for _, casei := range lockorder {
cas = &scases[casei]
c = cas.c c = cas.c
sg := acquireSudog() sg := acquireSudog()
sg.g = gp sg.g = gp
...@@ -388,9 +390,10 @@ loop: ...@@ -388,9 +390,10 @@ loop:
if t0 != 0 { if t0 != 0 {
sg.releasetime = -1 sg.releasetime = -1
} }
sg.waitlink = gp.waiting
sg.c = c sg.c = c
gp.waiting = sg // Construct waiting list in lock order.
*nextp = sg
nextp = &sg.waitlink
switch cas.kind { switch cas.kind {
case caseRecv: case caseRecv:
...@@ -413,8 +416,7 @@ loop: ...@@ -413,8 +416,7 @@ loop:
// pass 3 - dequeue from unsuccessful chans // pass 3 - dequeue from unsuccessful chans
// otherwise they stack up on quiet channels // otherwise they stack up on quiet channels
// record the successful case, if any. // record the successful case, if any.
// We singly-linked up the SudoGs in case order, so when // We singly-linked up the SudoGs in lock order.
// iterating through the linked list they are in reverse order.
cas = nil cas = nil
sglist = gp.waiting sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting. // Clear all elem before unlinking from gp.waiting.
...@@ -424,8 +426,9 @@ loop: ...@@ -424,8 +426,9 @@ loop:
sg1.c = nil sg1.c = nil
} }
gp.waiting = nil gp.waiting = nil
for i := int(sel.ncase) - 1; i >= 0; i-- {
k = &scases[pollorder[i]] for _, casei := range lockorder {
k = &scases[casei]
if sglist.releasetime > 0 { if sglist.releasetime > 0 {
k.releasetime = sglist.releasetime k.releasetime = sglist.releasetime
} }
......
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