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,7 +172,6 @@ asynch: ...@@ -172,7 +172,6 @@ asynch:
} }
if(raceenabled) { 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·racerelease(chanbuf(c, c->sendx));
} }
...@@ -304,7 +303,6 @@ asynch: ...@@ -304,7 +303,6 @@ asynch:
if(raceenabled) { if(raceenabled) {
runtime·raceacquire(chanbuf(c, c->recvx)); runtime·raceacquire(chanbuf(c, c->recvx));
if(c->dataqsiz == 1)
runtime·racerelease(chanbuf(c, c->recvx)); runtime·racerelease(chanbuf(c, c->recvx));
} }
...@@ -855,7 +853,6 @@ asyncrecv: ...@@ -855,7 +853,6 @@ asyncrecv:
if(cas->sg.elem != nil) if(cas->sg.elem != nil)
runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv); runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
runtime·raceacquire(chanbuf(c, c->recvx)); 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) if(cas->receivedp != nil)
...@@ -881,7 +878,6 @@ asyncrecv: ...@@ -881,7 +878,6 @@ asyncrecv:
asyncsend: asyncsend:
// can send to buffer // can send to buffer
if(raceenabled) { 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·racerelease(chanbuf(c, c->sendx));
runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend); runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
......
...@@ -567,22 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) { ...@@ -567,22 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) {
v = 2 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) { func TestRaceChanCloseSend(t *testing.T) {
compl := make(chan bool, 1) compl := make(chan bool, 1)
c := make(chan int, 10) c := make(chan int, 10)
...@@ -641,16 +625,35 @@ func TestNoRaceSelectMutex(t *testing.T) { ...@@ -641,16 +625,35 @@ func TestNoRaceSelectMutex(t *testing.T) {
func TestRaceChanSem(t *testing.T) { func TestRaceChanSem(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
mtx := make(chan struct{}, 2) mtx := make(chan bool, 2)
data := 0 data := 0
go func() { go func() {
mtx <- struct{}{} mtx <- true
data = 42 data = 42
<-mtx <-mtx
done <- struct{}{} done <- struct{}{}
}() }()
mtx <- struct{}{} mtx <- true
data = 43 data = 43
<-mtx <-mtx
<-done <-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