if(debug['w'] > 1)
dump("racewalk-before", n);
setlineno(n);
- if(init == nil || init == &n->ninit)
+ if(init == nil)
fatal("racewalk: bad init list");
+ if(init == &n->ninit) {
+ // If init == &n->ninit and n->ninit is non-nil,
+ // racewalknode might append it to itself.
+ // nil it out and handle it separately before putting it back.
+ l = n->ninit;
+ n->ninit = nil;
+ racewalklist(l, nil);
+ racewalknode(&n, &l, wr, skip); // recurse with nil n->ninit
+ appendinit(&n, l);
+ *np = n;
+ return;
+ }
racewalklist(n->ninit, nil);
// side effects are safe.
// n->right may not be executed,
// so instrumentation goes to n->right->ninit, not init.
- // If right->ninit is non-nil, racewalknode might append it to itself.
- // nil it out and handle it separately before putting it back.
- l = n->right->ninit;
- n->right->ninit = nil;
- racewalklist(l, nil);
- racewalknode(&n->right, &l, wr, 0);
- appendinit(&n->right, l);
+ racewalknode(&n->right, &n->right->ninit, wr, 0);
goto ret;
case ONAME:
ret:
if(n->op != OBLOCK) // OBLOCK is handled above in a special way.
racewalklist(n->list, init);
- l = nil;
- racewalknode(&n->ntest, &l, 0, 0);
- n->ninit = concat(n->ninit, l);
- l = nil;
- racewalknode(&n->nincr, &l, 0, 0);
- n->ninit = concat(n->ninit, l);
+ racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
+ racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
racewalklist(n->nbody, nil);
racewalklist(n->nelse, nil);
racewalklist(n->rlist, nil);
}
}
+func TestRaceForInit(t *testing.T) {
+ c := make(chan int)
+ x := 0
+ go func() {
+ c <- x
+ }()
+ for x = 42; false; {
+ }
+ <-c
+}
+
+func TestNoRaceForInit(t *testing.T) {
+ done := make(chan bool)
+ c := make(chan bool)
+ x := 0
+ go func() {
+ for {
+ _, ok := <-c
+ if !ok {
+ done <- true
+ return
+ }
+ x++
+ }
+ }()
+ i := 0
+ for x = 42; i < 10; i++ {
+ c <- true
+ }
+ close(c)
+ <-done
+}
+
+func TestRaceForTest(t *testing.T) {
+ done := make(chan bool)
+ c := make(chan bool)
+ stop := false
+ go func() {
+ for {
+ _, ok := <-c
+ if !ok {
+ done <- true
+ return
+ }
+ stop = true
+ }
+ }()
+ for !stop {
+ c <- true
+ }
+ close(c)
+ <-done
+}
+
+func TestRaceForIncr(t *testing.T) {
+ done := make(chan bool)
+ c := make(chan bool)
+ x := 0
+ go func() {
+ for {
+ _, ok := <-c
+ if !ok {
+ done <- true
+ return
+ }
+ x++
+ }
+ }()
+ for i := 0; i < 10; x++ {
+ i++
+ c <- true
+ }
+ close(c)
+ <-done
+}
+
+func TestNoRaceForIncr(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ go func() {
+ x++
+ done <- true
+ }()
+ for i := 0; i < 0; x++ {
+ }
+ <-done
+}
+
func TestRacePlus(t *testing.T) {
var x, y, z int
ch := make(chan int, 2)