]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: put g.waiting list in lock order
authorAustin Clements <austin@google.com>
Tue, 16 Feb 2016 16:06:00 +0000 (11:06 -0500)
committerAustin Clements <austin@google.com>
Wed, 16 Mar 2016 20:13:07 +0000 (20:13 +0000)
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/20037
Reviewed-by: Rick Hudson <rlh@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Austin Clements <austin@google.com>

src/runtime/runtime2.go
src/runtime/select.go

index ac437def263164ff0bc1ad49a541859181c47769..5d7f4354efc1235ef519b9f6d22c50c1da57cc39 100644 (file)
@@ -314,7 +314,7 @@ type g struct {
        gopc           uintptr // pc of go statement that created this goroutine
        startpc        uintptr // pc of goroutine function
        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
 
index 6e016acfa073cf4387b119b5f524d9c4600b6e17..444427ccb7d36bbf8c82a8341e72d85226249d7a 100644 (file)
@@ -319,6 +319,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
                sglist *sudog
                sgnext *sudog
                qp     unsafe.Pointer
+               nextp  **sudog
        )
 
 loop:
@@ -374,8 +375,9 @@ loop:
        if gp.waiting != nil {
                throw("gp.waiting != nil")
        }
-       for i := 0; i < int(sel.ncase); i++ {
-               cas = &scases[pollorder[i]]
+       nextp = &gp.waiting
+       for _, casei := range lockorder {
+               cas = &scases[casei]
                c = cas.c
                sg := acquireSudog()
                sg.g = gp
@@ -388,9 +390,10 @@ loop:
                if t0 != 0 {
                        sg.releasetime = -1
                }
-               sg.waitlink = gp.waiting
                sg.c = c
-               gp.waiting = sg
+               // Construct waiting list in lock order.
+               *nextp = sg
+               nextp = &sg.waitlink
 
                switch cas.kind {
                case caseRecv:
@@ -413,8 +416,7 @@ loop:
        // pass 3 - dequeue from unsuccessful chans
        // otherwise they stack up on quiet channels
        // record the successful case, if any.
-       // We singly-linked up the SudoGs in case order, so when
-       // iterating through the linked list they are in reverse order.
+       // We singly-linked up the SudoGs in lock order.
        cas = nil
        sglist = gp.waiting
        // Clear all elem before unlinking from gp.waiting.
@@ -424,8 +426,9 @@ loop:
                sg1.c = 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 {
                        k.releasetime = sglist.releasetime
                }