mirror of
https://github.com/golang/go
synced 2024-11-11 23:20:24 -07:00
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
This commit is contained in:
parent
f8c350873c
commit
d89a738378
@ -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);
|
||||
}
|
||||
|
65
src/pkg/runtime/race/testdata/chan_test.go
vendored
65
src/pkg/runtime/race/testdata/chan_test.go
vendored
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user