]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix select pass 3
authorHector Chu <hectorchu@gmail.com>
Mon, 18 Jul 2011 20:15:01 +0000 (16:15 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 18 Jul 2011 20:15:01 +0000 (16:15 -0400)
Fixes #2075

R=rsc, ken, r
CC=golang-dev
https://golang.org/cl/4748045

src/pkg/runtime/chan.c
test/chan/select6.go [new file with mode: 0644]

index efaceebf5a346a1c25e654e895dc77d16374fa3f..bbe05e041c78646e2594ea1492e97078bfa5b1a5 100644 (file)
@@ -1167,12 +1167,15 @@ loop:
 static void
 dequeueg(WaitQ *q, Hchan *c)
 {
-       SudoG **l, *sgp;
-       
-       for(l=&q->first; (sgp=*l) != nil; l=&sgp->link) {
+       SudoG **l, *sgp, *prevsgp;
+
+       prevsgp = nil;
+       for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
                if(sgp->g == g) {
                        *l = sgp->link;
                        freesg(c, sgp);
+                       if(q->last == sgp)
+                               q->last = prevsgp;
                        break;
                }
        }
diff --git a/test/chan/select6.go b/test/chan/select6.go
new file mode 100644 (file)
index 0000000..2ba6810
--- /dev/null
@@ -0,0 +1,34 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 2075
+// A bug in select corrupts channel queues of failed cases
+// if there are multiple waiters on those channels and the
+// select is the last in the queue. If further waits are made
+// on the channel without draining it first then those waiters
+// will never wake up. In the code below c1 is such a channel.
+
+package main
+
+func main() {
+       c1 := make(chan bool)
+       c2 := make(chan bool)
+       c3 := make(chan bool)
+       go func() { <-c1 }()
+       go func() {
+               select {
+               case <-c1:
+                       panic("dummy")
+               case <-c2:
+                       c3 <- true
+               }
+               <-c1
+       }()
+       go func() { c2 <- true }()
+       <-c3
+       c1 <- true
+       c1 <- true
+}