diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2014-03-26 19:05:48 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2014-03-26 19:05:48 +0400 |
| commit | d89a73837878fa16697e98ff1adf249eef5eaa05 (patch) | |
| tree | 23a2cf338e630ed717cff37e32d6af81337c4ed0 /src | |
| parent | f8c350873c94baaf53b9c1c2b6ddfb463172c3de (diff) | |
| download | go-d89a73837878fa16697e98ff1adf249eef5eaa05.tar.xz | |
runtime: support channel-based mutex in race detector
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/pkg/runtime/chan.goc | 14 | ||||
| -rw-r--r-- | src/pkg/runtime/race/testdata/chan_test.go | 65 |
2 files changed, 76 insertions, 3 deletions
diff --git a/src/pkg/runtime/chan.goc b/src/pkg/runtime/chan.goc index 7442715e78..185219640c 100644 --- a/src/pkg/runtime/chan.goc +++ b/src/pkg/runtime/chan.goc @@ -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); } diff --git a/src/pkg/runtime/race/testdata/chan_test.go b/src/pkg/runtime/race/testdata/chan_test.go index d6a1f14db1..aab59a553d 100644 --- a/src/pkg/runtime/race/testdata/chan_test.go +++ b/src/pkg/runtime/race/testdata/chan_test.go @@ -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 +} |
