Commit cb86d867 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime/race: race instrument reads/writes in select cases

The new select tests currently fail (the race is not detected).

R=khr
CC=golang-codereviews
https://golang.org/cl/54220043
parent 98b50b89
...@@ -41,7 +41,7 @@ struct Hchan ...@@ -41,7 +41,7 @@ struct Hchan
uint16 elemsize; uint16 elemsize;
uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
bool closed; bool closed;
Alg* elemalg; // interface for element type Type* elemtype; // element type
uintgo sendx; // send index uintgo sendx; // send index
uintgo recvx; // receive index uintgo recvx; // receive index
WaitQ recvq; // list of recv waiters WaitQ recvq; // list of recv waiters
...@@ -110,7 +110,7 @@ runtime·makechan_c(ChanType *t, int64 hint) ...@@ -110,7 +110,7 @@ runtime·makechan_c(ChanType *t, int64 hint)
// allocate memory in one call // allocate memory in one call
c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0); c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0);
c->elemsize = elem->size; c->elemsize = elem->size;
c->elemalg = elem->alg; c->elemtype = elem;
c->dataqsiz = hint; c->dataqsiz = hint;
if(debug) if(debug)
...@@ -174,7 +174,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc) ...@@ -174,7 +174,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(debug) { if(debug) {
runtime·printf("chansend: chan=%p; elem=", c); runtime·printf("chansend: chan=%p; elem=", c);
c->elemalg->print(c->elemsize, ep); c->elemtype->alg->print(c->elemsize, ep);
runtime·prints("\n"); runtime·prints("\n");
} }
...@@ -203,7 +203,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc) ...@@ -203,7 +203,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
if(sg->elem != nil) if(sg->elem != nil)
c->elemalg->copy(c->elemsize, sg->elem, ep); c->elemtype->alg->copy(c->elemsize, sg->elem, ep);
if(sg->releasetime) if(sg->releasetime)
sg->releasetime = runtime·cputicks(); sg->releasetime = runtime·cputicks();
runtime·ready(gp); runtime·ready(gp);
...@@ -261,7 +261,7 @@ asynch: ...@@ -261,7 +261,7 @@ asynch:
if(raceenabled) if(raceenabled)
runtime·racerelease(chanbuf(c, c->sendx)); runtime·racerelease(chanbuf(c, c->sendx));
c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep); c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
if(++c->sendx == c->dataqsiz) if(++c->sendx == c->dataqsiz)
c->sendx = 0; c->sendx = 0;
c->qcount++; c->qcount++;
...@@ -331,7 +331,7 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive ...@@ -331,7 +331,7 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
runtime·unlock(c); runtime·unlock(c);
if(ep != nil) if(ep != nil)
c->elemalg->copy(c->elemsize, ep, sg->elem); c->elemtype->alg->copy(c->elemsize, ep, sg->elem);
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
if(sg->releasetime) if(sg->releasetime)
...@@ -397,8 +397,8 @@ asynch: ...@@ -397,8 +397,8 @@ asynch:
runtime·raceacquire(chanbuf(c, c->recvx)); runtime·raceacquire(chanbuf(c, c->recvx));
if(ep != nil) if(ep != nil)
c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx)); c->elemtype->alg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz) if(++c->recvx == c->dataqsiz)
c->recvx = 0; c->recvx = 0;
c->qcount--; c->qcount--;
...@@ -423,7 +423,7 @@ asynch: ...@@ -423,7 +423,7 @@ asynch:
closed: closed:
if(ep != nil) if(ep != nil)
c->elemalg->copy(c->elemsize, ep, nil); c->elemtype->alg->copy(c->elemsize, ep, nil);
if(selected != nil) if(selected != nil)
*selected = true; *selected = true;
if(received != nil) if(received != nil)
...@@ -1007,18 +1007,28 @@ loop: ...@@ -1007,18 +1007,28 @@ loop:
*cas->receivedp = true; *cas->receivedp = true;
} }
if(raceenabled) {
if(cas->kind == CaseRecv && cas->sg.elem != nil)
runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, runtime·chanrecv);
else if(cas->kind == CaseSend)
runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, runtime·chansend);
}
selunlock(sel); selunlock(sel);
goto retc; goto retc;
asyncrecv: asyncrecv:
// can receive from buffer // can receive from buffer
if(raceenabled) if(raceenabled) {
if(cas->sg.elem != nil)
runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, runtime·chanrecv);
runtime·raceacquire(chanbuf(c, c->recvx)); runtime·raceacquire(chanbuf(c, c->recvx));
}
if(cas->receivedp != nil) if(cas->receivedp != nil)
*cas->receivedp = true; *cas->receivedp = true;
if(cas->sg.elem != nil) if(cas->sg.elem != nil)
c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx)); c->elemtype->alg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz) if(++c->recvx == c->dataqsiz)
c->recvx = 0; c->recvx = 0;
c->qcount--; c->qcount--;
...@@ -1036,9 +1046,11 @@ asyncrecv: ...@@ -1036,9 +1046,11 @@ asyncrecv:
asyncsend: asyncsend:
// can send to buffer // can send to buffer
if(raceenabled) if(raceenabled) {
runtime·racerelease(chanbuf(c, c->sendx)); runtime·racerelease(chanbuf(c, c->sendx));
c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem); runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, runtime·chansend);
}
c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
if(++c->sendx == c->dataqsiz) if(++c->sendx == c->dataqsiz)
c->sendx = 0; c->sendx = 0;
c->qcount++; c->qcount++;
...@@ -1056,15 +1068,18 @@ asyncsend: ...@@ -1056,15 +1068,18 @@ asyncsend:
syncrecv: syncrecv:
// can receive from sleeping sender (sg) // can receive from sleeping sender (sg)
if(raceenabled) if(raceenabled) {
if(cas->sg.elem != nil)
runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, runtime·chanrecv);
racesync(c, sg); racesync(c, sg);
}
selunlock(sel); selunlock(sel);
if(debug) if(debug)
runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->receivedp != nil) if(cas->receivedp != nil)
*cas->receivedp = true; *cas->receivedp = true;
if(cas->sg.elem != nil) if(cas->sg.elem != nil)
c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem); c->elemtype->alg->copy(c->elemsize, cas->sg.elem, sg->elem);
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
if(sg->releasetime) if(sg->releasetime)
...@@ -1078,20 +1093,22 @@ rclose: ...@@ -1078,20 +1093,22 @@ rclose:
if(cas->receivedp != nil) if(cas->receivedp != nil)
*cas->receivedp = false; *cas->receivedp = false;
if(cas->sg.elem != nil) if(cas->sg.elem != nil)
c->elemalg->copy(c->elemsize, cas->sg.elem, nil); c->elemtype->alg->copy(c->elemsize, cas->sg.elem, nil);
if(raceenabled) if(raceenabled)
runtime·raceacquire(c); runtime·raceacquire(c);
goto retc; goto retc;
syncsend: syncsend:
// can send to sleeping receiver (sg) // can send to sleeping receiver (sg)
if(raceenabled) if(raceenabled) {
runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, runtime·chansend);
racesync(c, sg); racesync(c, sg);
}
selunlock(sel); selunlock(sel);
if(debug) if(debug)
runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(sg->elem != nil) if(sg->elem != nil)
c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); c->elemtype->alg->copy(c->elemsize, sg->elem, cas->sg.elem);
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
if(sg->releasetime) if(sg->releasetime)
......
...@@ -347,6 +347,119 @@ func TestRaceChanSendSelectClose(t *testing.T) { ...@@ -347,6 +347,119 @@ func TestRaceChanSendSelectClose(t *testing.T) {
<-compl <-compl
} }
func TestRaceSelectReadWriteAsync(t *testing.T) {
done := make(chan bool)
x := 0
c1 := make(chan int, 10)
c2 := make(chan int, 10)
c3 := make(chan int)
c2 <- 1
go func() {
select {
case c1 <- x: // read of x races with...
case c3 <- 1:
}
done <- true
}()
select {
case x = <-c2: // ... write to x here
case c3 <- 1:
}
<-done
}
func TestRaceSelectReadWriteSync(t *testing.T) {
done := make(chan bool)
x := 0
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
// make c1 and c2 ready for communication
go func() {
<-c1
}()
go func() {
c2 <- 1
}()
go func() {
select {
case c1 <- x: // read of x races with...
case c3 <- 1:
}
done <- true
}()
select {
case x = <-c2: // ... write to x here
case c3 <- 1:
}
<-done
}
func TestNoRaceSelectReadWriteAsync(t *testing.T) {
done := make(chan bool)
x := 0
c1 := make(chan int)
c2 := make(chan int)
go func() {
select {
case c1 <- x: // read of x does not race with...
case c2 <- 1:
}
done <- true
}()
select {
case x = <-c1: // ... write to x here
case c2 <- 1:
}
<-done
}
func TestRaceChanReadWriteAsync(t *testing.T) {
done := make(chan bool)
c1 := make(chan int, 10)
c2 := make(chan int, 10)
c2 <- 10
x := 0
go func() {
c1 <- x // read of x races with...
done <- true
}()
x = <-c2 // ... write to x here
<-done
}
func TestRaceChanReadWriteSync(t *testing.T) {
done := make(chan bool)
c1 := make(chan int)
c2 := make(chan int)
// make c1 and c2 ready for communication
go func() {
<-c1
}()
go func() {
c2 <- 10
}()
x := 0
go func() {
c1 <- x // read of x races with...
done <- true
}()
x = <-c2 // ... write to x here
<-done
}
func TestNoRaceChanReadWriteAsync(t *testing.T) {
done := make(chan bool)
c1 := make(chan int, 10)
x := 0
go func() {
c1 <- x // read of x does not race with...
done <- true
}()
x = <-c1 // ... write to x here
<-done
}
func TestNoRaceProducerConsumerUnbuffered(t *testing.T) { func TestNoRaceProducerConsumerUnbuffered(t *testing.T) {
type Task struct { type Task struct {
f func() f func()
......
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