2011-10-06 09:42:51 -06:00
|
|
|
// Copyright 2011 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.
|
|
|
|
|
|
|
|
package runtime_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
"testing"
|
2013-07-29 09:43:08 -06:00
|
|
|
"time"
|
2011-10-06 09:42:51 -06:00
|
|
|
)
|
|
|
|
|
2013-08-14 12:54:31 -06:00
|
|
|
type Tintptr *int // assignable to *int
|
|
|
|
type Tint int // *Tint implements Tinter, interface{}
|
|
|
|
|
|
|
|
func (t *Tint) m() {}
|
|
|
|
|
|
|
|
type Tinter interface {
|
|
|
|
m()
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFinalizerType(t *testing.T) {
|
2013-07-29 09:43:08 -06:00
|
|
|
if runtime.GOARCH != "amd64" {
|
|
|
|
t.Skipf("Skipping on non-amd64 machine")
|
|
|
|
}
|
2013-08-14 12:54:31 -06:00
|
|
|
|
|
|
|
ch := make(chan bool, 10)
|
|
|
|
finalize := func(x *int) {
|
|
|
|
if *x != 97531 {
|
|
|
|
t.Errorf("finalizer %d, want %d", *x, 97531)
|
|
|
|
}
|
|
|
|
ch <- true
|
2013-07-29 09:43:08 -06:00
|
|
|
}
|
|
|
|
|
2013-08-14 12:54:31 -06:00
|
|
|
var finalizerTests = []struct {
|
|
|
|
convert func(*int) interface{}
|
|
|
|
finalizer interface{}
|
|
|
|
}{
|
|
|
|
{func(x *int) interface{} { return x }, func(v *int) { finalize(v) }},
|
|
|
|
{func(x *int) interface{} { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
|
|
|
|
{func(x *int) interface{} { return Tintptr(x) }, func(v *int) { finalize(v) }},
|
|
|
|
{func(x *int) interface{} { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
|
|
|
|
{func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
|
2013-07-29 09:43:08 -06:00
|
|
|
}
|
2013-08-14 12:54:31 -06:00
|
|
|
|
|
|
|
for _, tt := range finalizerTests {
|
2013-12-19 13:37:44 -07:00
|
|
|
done := make(chan bool, 1)
|
2013-10-02 10:30:49 -06:00
|
|
|
go func() {
|
2013-08-14 12:54:31 -06:00
|
|
|
v := new(int)
|
|
|
|
*v = 97531
|
|
|
|
runtime.SetFinalizer(tt.convert(v), tt.finalizer)
|
|
|
|
v = nil
|
2013-12-19 13:37:44 -07:00
|
|
|
done <- true
|
2013-08-14 12:54:31 -06:00
|
|
|
}()
|
2013-12-19 13:37:44 -07:00
|
|
|
<-done
|
2013-08-14 12:54:31 -06:00
|
|
|
runtime.GC()
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
case <-time.After(time.Second * 4):
|
2013-10-02 10:30:49 -06:00
|
|
|
t.Errorf("finalizer for type %T didn't run", tt.finalizer)
|
2013-08-14 12:54:31 -06:00
|
|
|
}
|
2013-07-29 09:43:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type bigValue struct {
|
|
|
|
fill uint64
|
|
|
|
it bool
|
|
|
|
up string
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFinalizerInterfaceBig(t *testing.T) {
|
|
|
|
if runtime.GOARCH != "amd64" {
|
|
|
|
t.Skipf("Skipping on non-amd64 machine")
|
|
|
|
}
|
|
|
|
ch := make(chan bool)
|
2013-12-19 13:37:44 -07:00
|
|
|
done := make(chan bool, 1)
|
2013-10-02 10:30:49 -06:00
|
|
|
go func() {
|
2013-07-29 09:43:08 -06:00
|
|
|
v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
|
2013-10-02 10:30:49 -06:00
|
|
|
old := *v
|
2013-07-29 09:43:08 -06:00
|
|
|
runtime.SetFinalizer(v, func(v interface{}) {
|
|
|
|
i, ok := v.(*bigValue)
|
|
|
|
if !ok {
|
2013-10-02 10:30:49 -06:00
|
|
|
t.Errorf("finalizer called with type %T, want *bigValue", v)
|
2013-07-29 09:43:08 -06:00
|
|
|
}
|
2013-10-02 10:30:49 -06:00
|
|
|
if *i != old {
|
|
|
|
t.Errorf("finalizer called with %+v, want %+v", *i, old)
|
2013-07-29 09:43:08 -06:00
|
|
|
}
|
|
|
|
close(ch)
|
|
|
|
})
|
|
|
|
v = nil
|
2013-12-19 13:37:44 -07:00
|
|
|
done <- true
|
2013-07-29 09:43:08 -06:00
|
|
|
}()
|
2013-12-19 13:37:44 -07:00
|
|
|
<-done
|
2013-07-29 09:43:08 -06:00
|
|
|
runtime.GC()
|
|
|
|
select {
|
|
|
|
case <-ch:
|
2013-10-02 10:30:49 -06:00
|
|
|
case <-time.After(4 * time.Second):
|
|
|
|
t.Errorf("finalizer for type *bigValue didn't run")
|
2013-07-29 09:43:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-06 09:42:51 -06:00
|
|
|
func fin(v *int) {
|
|
|
|
}
|
|
|
|
|
2013-12-17 15:18:58 -07:00
|
|
|
// Verify we don't crash at least. golang.org/issue/6857
|
|
|
|
func TestFinalizerZeroSizedStruct(t *testing.T) {
|
|
|
|
type Z struct{}
|
|
|
|
z := new(Z)
|
|
|
|
runtime.SetFinalizer(z, func(*Z) {})
|
|
|
|
}
|
|
|
|
|
2011-10-06 09:42:51 -06:00
|
|
|
func BenchmarkFinalizer(b *testing.B) {
|
2014-02-24 09:50:12 -07:00
|
|
|
const Batch = 1000
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
var data [Batch]*int
|
|
|
|
for i := 0; i < Batch; i++ {
|
|
|
|
data[i] = new(int)
|
|
|
|
}
|
|
|
|
for pb.Next() {
|
|
|
|
for i := 0; i < Batch; i++ {
|
|
|
|
runtime.SetFinalizer(data[i], fin)
|
2011-10-06 09:42:51 -06:00
|
|
|
}
|
2014-02-24 09:50:12 -07:00
|
|
|
for i := 0; i < Batch; i++ {
|
|
|
|
runtime.SetFinalizer(data[i], nil)
|
2011-10-06 09:42:51 -06:00
|
|
|
}
|
2014-02-24 09:50:12 -07:00
|
|
|
}
|
|
|
|
})
|
2011-10-06 09:42:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkFinalizerRun(b *testing.B) {
|
2014-02-24 09:50:12 -07:00
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
v := new(int)
|
|
|
|
runtime.SetFinalizer(v, fin)
|
|
|
|
}
|
|
|
|
})
|
2011-10-06 09:42:51 -06:00
|
|
|
}
|