Commit 9e1cadad authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

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
parent f4ecfaa4
......@@ -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);
}
......
......@@ -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]
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment