]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: support channel-based mutex in race detector
authorDmitriy Vyukov <dvyukov@google.com>
Wed, 26 Mar 2014 15:05:48 +0000 (19:05 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Wed, 26 Mar 2014 15:05:48 +0000 (19:05 +0400)
Update channel race annotations to support change in
cl/75130045: doc: allow buffered channel as semaphore without initialization
The new annotations are added only for channels with capacity 1.
Strictly saying it's possible to construct a counter-example that
will produce a false positive with capacity > 1. But it's hardly can
lead to false positives in real programs, at least I would like to see such programs first.
Any additional annotations also increase probability of false negatives,
so I would prefer to add them lazily.

LGTM=rsc
R=golang-codereviews
CC=golang-codereviews, iant, khr, rsc
https://golang.org/cl/76970043

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

index 7442715e789e89699ebf592b0f9bf2e2202ac4ca..185219640c731968e16e0c6909de99549a4a2aee 100644 (file)
@@ -171,8 +171,11 @@ asynch:
                goto asynch;
        }
 
-       if(raceenabled)
+       if(raceenabled) {
+               if(c->dataqsiz == 1)
+                       runtime·raceacquire(chanbuf(c, c->sendx));
                runtime·racerelease(chanbuf(c, c->sendx));
+       }
 
        c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
        if(++c->sendx == c->dataqsiz)
@@ -299,8 +302,11 @@ asynch:
                goto asynch;
        }
 
-       if(raceenabled)
+       if(raceenabled) {
                runtime·raceacquire(chanbuf(c, c->recvx));
+               if(c->dataqsiz == 1)
+                       runtime·racerelease(chanbuf(c, c->recvx));
+       }
 
        if(ep != nil)
                c->elemtype->alg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
@@ -849,6 +855,8 @@ 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));
        }
        if(cas->receivedp != nil)
                *cas->receivedp = true;
@@ -873,6 +881,8 @@ asyncrecv:
 asyncsend:
        // can send to buffer
        if(raceenabled) {
+               if(c->dataqsiz == 1)
+                       runtime·raceacquire(chanbuf(c, c->sendx));
                runtime·racerelease(chanbuf(c, c->sendx));
                runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
        }
index d6a1f14db19c5062d2468614a250e19565b5e394..aab59a553d4b1b0843491f9c700a0026f80d32c9 100644 (file)
@@ -568,12 +568,14 @@ func TestRaceChanCloseLen(t *testing.T) {
 }
 
 func TestRaceChanSameCell(t *testing.T) {
-       c := make(chan int, 1)
+       c := make(chan int, 2)
        v := 0
        go func() {
                v = 1
                c <- 42
                <-c
+               c <- 42
+               <-c
        }()
        time.Sleep(1e7)
        c <- 43
@@ -591,3 +593,64 @@ func TestRaceChanCloseSend(t *testing.T) {
        c <- 0
        <-compl
 }
+
+func TestNoRaceChanMutex(t *testing.T) {
+       done := make(chan struct{})
+       mtx := make(chan struct{}, 1)
+       data := 0
+       go func() {
+               mtx <- struct{}{}
+               data = 42
+               <-mtx
+               done <- struct{}{}
+       }()
+       mtx <- struct{}{}
+       data = 43
+       <-mtx
+       <-done
+}
+
+func TestNoRaceSelectMutex(t *testing.T) {
+       done := make(chan struct{})
+       mtx := make(chan struct{}, 1)
+       aux := make(chan bool)
+       data := 0
+       go func() {
+               select {
+               case mtx <- struct{}{}:
+               case <-aux:
+               }
+               data = 42
+               select {
+               case <-mtx:
+               case <-aux:
+               }
+               done <- struct{}{}
+       }()
+       select {
+       case mtx <- struct{}{}:
+       case <-aux:
+       }
+       data = 43
+       select {
+       case <-mtx:
+       case <-aux:
+       }
+       <-done
+}
+
+func TestRaceChanSem(t *testing.T) {
+       done := make(chan struct{})
+       mtx := make(chan struct{}, 2)
+       data := 0
+       go func() {
+               mtx <- struct{}{}
+               data = 42
+               <-mtx
+               done <- struct{}{}
+       }()
+       mtx <- struct{}{}
+       data = 43
+       <-mtx
+       <-done
+}