blob: 5171dfc72e22af8f3e1c5d3c46f7a5bd0c6309b9 [file] [log] [blame]
// 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
}
}
}
}