From 9e1cadad0f64698636d4dd7a3543619b3cb269a3 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 8 Apr 2014 10:18:20 +0400 Subject: [PATCH] runtime/race: more precise handling of channel synchronization 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 | 12 +++---- src/pkg/runtime/race/testdata/chan_test.go | 41 ++++++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/pkg/runtime/chan.goc b/src/pkg/runtime/chan.goc index 185219640c..7a584717bb 100644 --- a/src/pkg/runtime/chan.goc +++ b/src/pkg/runtime/chan.goc @@ -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); } diff --git a/src/pkg/runtime/race/testdata/chan_test.go b/src/pkg/runtime/race/testdata/chan_test.go index aab59a553d..4a3d5290f2 100644 --- a/src/pkg/runtime/race/testdata/chan_test.go +++ b/src/pkg/runtime/race/testdata/chan_test.go @@ -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] + } +}