diff options
Diffstat (limited to 'libgo/go/runtime/chan_test.go')
-rw-r--r-- | libgo/go/runtime/chan_test.go | 109 |
1 files changed, 107 insertions, 2 deletions
diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go index 6553509..4bd061d 100644 --- a/libgo/go/runtime/chan_test.go +++ b/libgo/go/runtime/chan_test.go @@ -578,7 +578,7 @@ func TestSelectDuplicateChannel(t *testing.T) { } e <- 9 }() - time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c + time.Sleep(time.Millisecond) // make sure goroutine A gets queued first on c // goroutine B go func() { @@ -591,6 +591,84 @@ func TestSelectDuplicateChannel(t *testing.T) { c <- 8 // wake up B. This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B) } +var selectSink interface{} + +func TestSelectStackAdjust(t *testing.T) { + // Test that channel receive slots that contain local stack + // pointers are adjusted correctly by stack shrinking. + c := make(chan *int) + d := make(chan *int) + ready1 := make(chan bool) + ready2 := make(chan bool) + + f := func(ready chan bool, dup bool) { + // Temporarily grow the stack to 10K. + stackGrowthRecursive((10 << 10) / (128 * 8)) + + // We're ready to trigger GC and stack shrink. + ready <- true + + val := 42 + var cx *int + cx = &val + + var c2 chan *int + var d2 chan *int + if dup { + c2 = c + d2 = d + } + + // Receive from d. cx won't be affected. + select { + case cx = <-c: + case <-c2: + case <-d: + case <-d2: + } + + // Check that pointer in cx was adjusted correctly. + if cx != &val { + t.Error("cx no longer points to val") + } else if val != 42 { + t.Error("val changed") + } else { + *cx = 43 + if val != 43 { + t.Error("changing *cx failed to change val") + } + } + ready <- true + } + + go f(ready1, false) + go f(ready2, true) + + // Let the goroutines get into the select. + <-ready1 + <-ready2 + time.Sleep(10 * time.Millisecond) + + // Force concurrent GC a few times. + var before, after runtime.MemStats + runtime.ReadMemStats(&before) + for i := 0; i < 100; i++ { + selectSink = new([1 << 20]byte) + runtime.ReadMemStats(&after) + if after.NumGC-before.NumGC >= 2 { + goto done + } + } + t.Fatal("failed to trigger concurrent GC") +done: + selectSink = nil + + // Wake selects. + close(d) + <-ready1 + <-ready2 +} + func BenchmarkChanNonblocking(b *testing.B) { myc := make(chan int) b.RunParallel(func(pb *testing.PB) { @@ -721,7 +799,7 @@ func BenchmarkChanContended(b *testing.B) { }) } -func BenchmarkChanSync(b *testing.B) { +func benchmarkChanSync(b *testing.B, work int) { const CallsPerSched = 1000 procs := 2 N := int32(b.N / CallsPerSched / procs * procs) @@ -737,10 +815,14 @@ func BenchmarkChanSync(b *testing.B) { for g := 0; g < CallsPerSched; g++ { if i%2 == 0 { <-myc + localWork(work) myc <- 0 + localWork(work) } else { myc <- 0 + localWork(work) <-myc + localWork(work) } } } @@ -752,6 +834,14 @@ func BenchmarkChanSync(b *testing.B) { } } +func BenchmarkChanSync(b *testing.B) { + benchmarkChanSync(b, 0) +} + +func BenchmarkChanSyncWork(b *testing.B) { + benchmarkChanSync(b, 1000) +} + func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) { const CallsPerSched = 1000 procs := runtime.GOMAXPROCS(-1) @@ -925,3 +1015,18 @@ func BenchmarkChanPopular(b *testing.B) { } wg.Wait() } + +var ( + alwaysFalse = false + workSink = 0 +) + +func localWork(w int) { + foo := 0 + for i := 0; i < w; i++ { + foo /= (foo + 1) + } + if alwaysFalse { + workSink += foo + } +} |