]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/race: more precise handling of channel synchronization
authorDmitriy Vyukov <dvyukov@google.com>
Tue, 8 Apr 2014 06:18:20 +0000 (10:18 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Tue, 8 Apr 2014 06:18:20 +0000 (10:18 +0400)
It turns out there is a relatively common pattern that relies on
inverted channel semaphore:

gate := make(chan bool, N)
for ... {
        // limit concurrency
        gate <- true
        go func() {
                foo(...)
                <-gate
        }()
}
// join all goroutines
for i := 0; i < N; i++ {
        gate <- true
}

So handle synchronization on inverted semaphores with cap>1.
Fixes #7718.

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/84880046

src/pkg/runtime/chan.goc
src/pkg/runtime/race/testdata/chan_test.go

index 185219640c731968e16e0c6909de99549a4a2aee..7a584717bb0705832b8cf7493c7ccba170c92df4 100644 (file)
@@ -172,8 +172,7 @@ asynch:
        }
 
        if(raceenabled) {
-               if(c->dataqsiz == 1)
-                       runtime·raceacquire(chanbuf(c, c->sendx));
+               runtime·raceacquire(chanbuf(c, c->sendx));
                runtime·racerelease(chanbuf(c, c->sendx));
        }
 
@@ -304,8 +303,7 @@ asynch:
 
        if(raceenabled) {
                runtime·raceacquire(chanbuf(c, c->recvx));
-               if(c->dataqsiz == 1)
-                       runtime·racerelease(chanbuf(c, c->recvx));
+               runtime·racerelease(chanbuf(c, c->recvx));
        }
 
        if(ep != nil)
@@ -855,8 +853,7 @@ asyncrecv:
                if(cas->sg.elem != nil)
                        runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
                runtime·raceacquire(chanbuf(c, c->recvx));
-               if(c->dataqsiz == 1)
-                       runtime·racerelease(chanbuf(c, c->recvx));
+               runtime·racerelease(chanbuf(c, c->recvx));
        }
        if(cas->receivedp != nil)
                *cas->receivedp = true;
@@ -881,8 +878,7 @@ asyncrecv:
 asyncsend:
        // can send to buffer
        if(raceenabled) {
-               if(c->dataqsiz == 1)
-                       runtime·raceacquire(chanbuf(c, c->sendx));
+               runtime·raceacquire(chanbuf(c, c->sendx));
                runtime·racerelease(chanbuf(c, c->sendx));
                runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
        }
index aab59a553d4b1b0843491f9c700a0026f80d32c9..4a3d5290f2a6cb80d9a12ceb1b01fb29003b0149 100644 (file)
@@ -567,22 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) {
        v = 2
 }
 
-func TestRaceChanSameCell(t *testing.T) {
-       c := make(chan int, 2)
-       v := 0
-       go func() {
-               v = 1
-               c <- 42
-               <-c
-               c <- 42
-               <-c
-       }()
-       time.Sleep(1e7)
-       c <- 43
-       <-c
-       _ = v
-}
-
 func TestRaceChanCloseSend(t *testing.T) {
        compl := make(chan bool, 1)
        c := make(chan int, 10)
@@ -641,16 +625,35 @@ func TestNoRaceSelectMutex(t *testing.T) {
 
 func TestRaceChanSem(t *testing.T) {
        done := make(chan struct{})
-       mtx := make(chan struct{}, 2)
+       mtx := make(chan bool, 2)
        data := 0
        go func() {
-               mtx <- struct{}{}
+               mtx <- true
                data = 42
                <-mtx
                done <- struct{}{}
        }()
-       mtx <- struct{}{}
+       mtx <- true
        data = 43
        <-mtx
        <-done
 }
+
+func TestNoRaceChanWaitGroup(t *testing.T) {
+       const N = 10
+       chanWg := make(chan bool, N/2)
+       data := make([]int, N)
+       for i := 0; i < N; i++ {
+               chanWg <- true
+               go func(i int) {
+                       data[i] = 42
+                       <-chanWg
+               }(i)
+       }
+       for i := 0; i < cap(chanWg); i++ {
+               chanWg <- true
+       }
+       for i := 0; i < N; i++ {
+               _ = data[i]
+       }
+}