mfinal_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package runtime_test
  5. import (
  6. "runtime"
  7. "testing"
  8. "time"
  9. "unsafe"
  10. )
  11. type Tintptr *int // assignable to *int
  12. type Tint int // *Tint implements Tinter, interface{}
  13. func (t *Tint) m() {}
  14. type Tinter interface {
  15. m()
  16. }
  17. func TestFinalizerType(t *testing.T) {
  18. if runtime.GOARCH != "amd64" {
  19. t.Skipf("Skipping on non-amd64 machine")
  20. }
  21. if runtime.Compiler == "gccgo" {
  22. t.Skip("skipping for gccgo")
  23. }
  24. ch := make(chan bool, 10)
  25. finalize := func(x *int) {
  26. if *x != 97531 {
  27. t.Errorf("finalizer %d, want %d", *x, 97531)
  28. }
  29. ch <- true
  30. }
  31. var finalizerTests = []struct {
  32. convert func(*int) interface{}
  33. finalizer interface{}
  34. }{
  35. {func(x *int) interface{} { return x }, func(v *int) { finalize(v) }},
  36. {func(x *int) interface{} { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
  37. {func(x *int) interface{} { return Tintptr(x) }, func(v *int) { finalize(v) }},
  38. {func(x *int) interface{} { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
  39. {func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
  40. }
  41. for i, tt := range finalizerTests {
  42. done := make(chan bool, 1)
  43. go func() {
  44. // allocate struct with pointer to avoid hitting tinyalloc.
  45. // Otherwise we can't be sure when the allocation will
  46. // be freed.
  47. type T struct {
  48. v int
  49. p unsafe.Pointer
  50. }
  51. v := &new(T).v
  52. *v = 97531
  53. runtime.SetFinalizer(tt.convert(v), tt.finalizer)
  54. v = nil
  55. done <- true
  56. }()
  57. <-done
  58. runtime.GC()
  59. select {
  60. case <-ch:
  61. case <-time.After(time.Second * 4):
  62. t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
  63. }
  64. }
  65. }
  66. type bigValue struct {
  67. fill uint64
  68. it bool
  69. up string
  70. }
  71. func TestFinalizerInterfaceBig(t *testing.T) {
  72. if runtime.GOARCH != "amd64" {
  73. t.Skipf("Skipping on non-amd64 machine")
  74. }
  75. if runtime.Compiler == "gccgo" {
  76. t.Skip("skipping for gccgo")
  77. }
  78. ch := make(chan bool)
  79. done := make(chan bool, 1)
  80. go func() {
  81. v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
  82. old := *v
  83. runtime.SetFinalizer(v, func(v interface{}) {
  84. i, ok := v.(*bigValue)
  85. if !ok {
  86. t.Errorf("finalizer called with type %T, want *bigValue", v)
  87. }
  88. if *i != old {
  89. t.Errorf("finalizer called with %+v, want %+v", *i, old)
  90. }
  91. close(ch)
  92. })
  93. v = nil
  94. done <- true
  95. }()
  96. <-done
  97. runtime.GC()
  98. select {
  99. case <-ch:
  100. case <-time.After(4 * time.Second):
  101. t.Errorf("finalizer for type *bigValue didn't run")
  102. }
  103. }
  104. func fin(v *int) {
  105. }
  106. // Verify we don't crash at least. golang.org/issue/6857
  107. func TestFinalizerZeroSizedStruct(t *testing.T) {
  108. type Z struct{}
  109. z := new(Z)
  110. runtime.SetFinalizer(z, func(*Z) {})
  111. }
  112. func BenchmarkFinalizer(b *testing.B) {
  113. const Batch = 1000
  114. b.RunParallel(func(pb *testing.PB) {
  115. var data [Batch]*int
  116. for i := 0; i < Batch; i++ {
  117. data[i] = new(int)
  118. }
  119. for pb.Next() {
  120. for i := 0; i < Batch; i++ {
  121. runtime.SetFinalizer(data[i], fin)
  122. }
  123. for i := 0; i < Batch; i++ {
  124. runtime.SetFinalizer(data[i], nil)
  125. }
  126. }
  127. })
  128. }
  129. func BenchmarkFinalizerRun(b *testing.B) {
  130. b.RunParallel(func(pb *testing.PB) {
  131. for pb.Next() {
  132. v := new(int)
  133. runtime.SetFinalizer(v, fin)
  134. }
  135. })
  136. }
  137. // One chunk must be exactly one sizeclass in size.
  138. // It should be a sizeclass not used much by others, so we
  139. // have a greater chance of finding adjacent ones.
  140. // size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
  141. const objsize = 320
  142. type objtype [objsize]byte
  143. func adjChunks() (*objtype, *objtype) {
  144. var s []*objtype
  145. for {
  146. c := new(objtype)
  147. for _, d := range s {
  148. if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
  149. return c, d
  150. }
  151. if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
  152. return d, c
  153. }
  154. }
  155. s = append(s, c)
  156. }
  157. }
  158. // Make sure an empty slice on the stack doesn't pin the next object in memory.
  159. func TestEmptySlice(t *testing.T) {
  160. if true { // disable until bug 7564 is fixed.
  161. return
  162. }
  163. if runtime.Compiler == "gccgo" {
  164. t.Skip("skipping for gccgo")
  165. }
  166. x, y := adjChunks()
  167. // the pointer inside xs points to y.
  168. xs := x[objsize:] // change objsize to objsize-1 and the test passes
  169. fin := make(chan bool, 1)
  170. runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
  171. runtime.GC()
  172. select {
  173. case <-fin:
  174. case <-time.After(4 * time.Second):
  175. t.Errorf("finalizer of next object in memory didn't run")
  176. }
  177. xsglobal = xs // keep empty slice alive until here
  178. }
  179. var xsglobal []byte
  180. func adjStringChunk() (string, *objtype) {
  181. b := make([]byte, objsize)
  182. for {
  183. s := string(b)
  184. t := new(objtype)
  185. p := *(*uintptr)(unsafe.Pointer(&s))
  186. q := uintptr(unsafe.Pointer(t))
  187. if p+objsize == q {
  188. return s, t
  189. }
  190. }
  191. }
  192. // Make sure an empty string on the stack doesn't pin the next object in memory.
  193. func TestEmptyString(t *testing.T) {
  194. if runtime.Compiler == "gccgo" {
  195. t.Skip("skipping for gccgo")
  196. }
  197. x, y := adjStringChunk()
  198. ss := x[objsize:] // change objsize to objsize-1 and the test passes
  199. fin := make(chan bool, 1)
  200. // set finalizer on string contents of y
  201. runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
  202. runtime.GC()
  203. select {
  204. case <-fin:
  205. case <-time.After(4 * time.Second):
  206. t.Errorf("finalizer of next string in memory didn't run")
  207. }
  208. ssglobal = ss // keep 0-length string live until here
  209. }
  210. var ssglobal string
  211. // Test for issue 7656.
  212. func TestFinalizerOnGlobal(t *testing.T) {
  213. runtime.SetFinalizer(Foo1, func(p *Object1) {})
  214. runtime.SetFinalizer(Foo2, func(p *Object2) {})
  215. runtime.SetFinalizer(Foo1, nil)
  216. runtime.SetFinalizer(Foo2, nil)
  217. }
  218. type Object1 struct {
  219. Something []byte
  220. }
  221. type Object2 struct {
  222. Something byte
  223. }
  224. var (
  225. Foo2 = &Object2{}
  226. Foo1 = &Object1{}
  227. )