Source file
src/runtime/mfinal_test.go
Documentation: runtime
1
2
3
4
5 package runtime_test
6
7 import (
8 "runtime"
9 "testing"
10 "time"
11 "unsafe"
12 )
13
14 type Tintptr *int
15 type Tint int
16
17 func (t *Tint) m() {}
18
19 type Tinter interface {
20 m()
21 }
22
23 func TestFinalizerType(t *testing.T) {
24 if runtime.GOARCH != "amd64" {
25 t.Skipf("Skipping on non-amd64 machine")
26 }
27
28 ch := make(chan bool, 10)
29 finalize := func(x *int) {
30 if *x != 97531 {
31 t.Errorf("finalizer %d, want %d", *x, 97531)
32 }
33 ch <- true
34 }
35
36 var finalizerTests = []struct {
37 convert func(*int) interface{}
38 finalizer interface{}
39 }{
40 {func(x *int) interface{} { return x }, func(v *int) { finalize(v) }},
41 {func(x *int) interface{} { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
42 {func(x *int) interface{} { return Tintptr(x) }, func(v *int) { finalize(v) }},
43 {func(x *int) interface{} { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
44 {func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
45 }
46
47 for i, tt := range finalizerTests {
48 done := make(chan bool, 1)
49 go func() {
50
51
52
53 type T struct {
54 v int
55 p unsafe.Pointer
56 }
57 v := &new(T).v
58 *v = 97531
59 runtime.SetFinalizer(tt.convert(v), tt.finalizer)
60 v = nil
61 done <- true
62 }()
63 <-done
64 runtime.GC()
65 select {
66 case <-ch:
67 case <-time.After(time.Second * 4):
68 t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
69 }
70 }
71 }
72
73 type bigValue struct {
74 fill uint64
75 it bool
76 up string
77 }
78
79 func TestFinalizerInterfaceBig(t *testing.T) {
80 if runtime.GOARCH != "amd64" {
81 t.Skipf("Skipping on non-amd64 machine")
82 }
83 ch := make(chan bool)
84 done := make(chan bool, 1)
85 go func() {
86 v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
87 old := *v
88 runtime.SetFinalizer(v, func(v interface{}) {
89 i, ok := v.(*bigValue)
90 if !ok {
91 t.Errorf("finalizer called with type %T, want *bigValue", v)
92 }
93 if *i != old {
94 t.Errorf("finalizer called with %+v, want %+v", *i, old)
95 }
96 close(ch)
97 })
98 v = nil
99 done <- true
100 }()
101 <-done
102 runtime.GC()
103 select {
104 case <-ch:
105 case <-time.After(4 * time.Second):
106 t.Errorf("finalizer for type *bigValue didn't run")
107 }
108 }
109
110 func fin(v *int) {
111 }
112
113
114 func TestFinalizerZeroSizedStruct(t *testing.T) {
115 type Z struct{}
116 z := new(Z)
117 runtime.SetFinalizer(z, func(*Z) {})
118 }
119
120 func BenchmarkFinalizer(b *testing.B) {
121 const Batch = 1000
122 b.RunParallel(func(pb *testing.PB) {
123 var data [Batch]*int
124 for i := 0; i < Batch; i++ {
125 data[i] = new(int)
126 }
127 for pb.Next() {
128 for i := 0; i < Batch; i++ {
129 runtime.SetFinalizer(data[i], fin)
130 }
131 for i := 0; i < Batch; i++ {
132 runtime.SetFinalizer(data[i], nil)
133 }
134 }
135 })
136 }
137
138 func BenchmarkFinalizerRun(b *testing.B) {
139 b.RunParallel(func(pb *testing.PB) {
140 for pb.Next() {
141 v := new(int)
142 runtime.SetFinalizer(v, fin)
143 }
144 })
145 }
146
147
148
149
150
151 const objsize = 320
152
153 type objtype [objsize]byte
154
155 func adjChunks() (*objtype, *objtype) {
156 var s []*objtype
157
158 for {
159 c := new(objtype)
160 for _, d := range s {
161 if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
162 return c, d
163 }
164 if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
165 return d, c
166 }
167 }
168 s = append(s, c)
169 }
170 }
171
172
173 func TestEmptySlice(t *testing.T) {
174 x, y := adjChunks()
175
176
177 xs := x[objsize:]
178
179 fin := make(chan bool, 1)
180 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
181 runtime.GC()
182 select {
183 case <-fin:
184 case <-time.After(4 * time.Second):
185 t.Errorf("finalizer of next object in memory didn't run")
186 }
187 xsglobal = xs
188 }
189
190 var xsglobal []byte
191
192 func adjStringChunk() (string, *objtype) {
193 b := make([]byte, objsize)
194 for {
195 s := string(b)
196 t := new(objtype)
197 p := *(*uintptr)(unsafe.Pointer(&s))
198 q := uintptr(unsafe.Pointer(t))
199 if p+objsize == q {
200 return s, t
201 }
202 }
203 }
204
205
206 func TestEmptyString(t *testing.T) {
207 x, y := adjStringChunk()
208
209 ss := x[objsize:]
210 fin := make(chan bool, 1)
211
212 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
213 runtime.GC()
214 select {
215 case <-fin:
216 case <-time.After(4 * time.Second):
217 t.Errorf("finalizer of next string in memory didn't run")
218 }
219 ssglobal = ss
220 }
221
222 var ssglobal string
223
224
225 func TestFinalizerOnGlobal(t *testing.T) {
226 runtime.SetFinalizer(Foo1, func(p *Object1) {})
227 runtime.SetFinalizer(Foo2, func(p *Object2) {})
228 runtime.SetFinalizer(Foo1, nil)
229 runtime.SetFinalizer(Foo2, nil)
230 }
231
232 type Object1 struct {
233 Something []byte
234 }
235
236 type Object2 struct {
237 Something byte
238 }
239
240 var (
241 Foo2 = &Object2{}
242 Foo1 = &Object1{}
243 )
244
245 func TestDeferKeepAlive(t *testing.T) {
246 if *flagQuick {
247 t.Skip("-quick")
248 }
249
250
251 t.Parallel()
252 type T *int
253 x := new(T)
254 finRun := false
255 runtime.SetFinalizer(x, func(x *T) {
256 finRun = true
257 })
258 defer runtime.KeepAlive(x)
259 runtime.GC()
260 time.Sleep(time.Second)
261 if finRun {
262 t.Errorf("finalizer ran prematurely")
263 }
264 }
265
View as plain text