diff options
Diffstat (limited to 'test/tinyfin.go')
-rw-r--r-- | test/tinyfin.go | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/test/tinyfin.go b/test/tinyfin.go new file mode 100644 index 0000000..5171dfc --- /dev/null +++ b/test/tinyfin.go @@ -0,0 +1,64 @@ +// run + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test finalizers work for tiny (combined) allocations. + +package main + +import ( + "runtime" + "time" +) + +func main() { + // Does not work on gccgo due to partially conservative GC. + // Try to enable when we have fully precise GC. + if runtime.Compiler == "gccgo" { + return + } + const N = 100 + finalized := make(chan int32, N) + for i := 0; i < N; i++ { + x := new(int32) // subject to tiny alloc + *x = int32(i) + // the closure must be big enough to be combined + runtime.SetFinalizer(x, func(p *int32) { + finalized <- *p + }) + } + runtime.GC() + count := 0 + done := make([]bool, N) + timeout := time.After(5*time.Second) + for { + select { + case <-timeout: + println("timeout,", count, "finalized so far") + panic("not all finalizers are called") + case x := <-finalized: + // Check that p points to the correct subobject of the tiny allocation. + // It's a bit tricky, because we can't capture another variable + // with the expected value (it would be combined as well). + if x < 0 || x >= N { + println("got", x) + panic("corrupted") + } + if done[x] { + println("got", x) + panic("already finalized") + } + done[x] = true + count++ + if count > N/10*9 { + // Some of the finalizers may not be executed, + // if the outermost allocations are combined with something persistent. + // Currently 4 int32's are combined into a 16-byte block, + // ensure that most of them are finalized. + return + } + } + } +} |