Source file
src/runtime/mfinal.go
Documentation: runtime
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "runtime/internal/atomic"
11 "runtime/internal/sys"
12 "unsafe"
13 )
14
15
16
17
18
19
20
21
22
23 type finblock struct {
24 alllink *finblock
25 next *finblock
26 cnt uint32
27 _ int32
28 fin [(_FinBlockSize - 2*sys.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
29 }
30
31 var finlock mutex
32 var fing *g
33 var finq *finblock
34 var finc *finblock
35 var finptrmask [_FinBlockSize / sys.PtrSize / 8]byte
36 var fingwait bool
37 var fingwake bool
38 var allfin *finblock
39
40
41 type finalizer struct {
42 fn *funcval
43 arg unsafe.Pointer
44 nret uintptr
45 fint *_type
46 ot *ptrtype
47 }
48
49 var finalizer1 = [...]byte{
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 1<<0 | 1<<1 | 0<<2 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 0<<7,
71 1<<0 | 1<<1 | 1<<2 | 1<<3 | 0<<4 | 1<<5 | 1<<6 | 1<<7,
72 1<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 | 0<<6 | 1<<7,
73 1<<0 | 1<<1 | 1<<2 | 0<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7,
74 0<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 | 1<<6 | 1<<7,
75 }
76
77 func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
78 if gcphase != _GCoff {
79
80
81
82
83
84
85 throw("queuefinalizer during GC")
86 }
87
88 lock(&finlock)
89 if finq == nil || finq.cnt == uint32(len(finq.fin)) {
90 if finc == nil {
91 finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
92 finc.alllink = allfin
93 allfin = finc
94 if finptrmask[0] == 0 {
95
96
97 if (unsafe.Sizeof(finalizer{}) != 5*sys.PtrSize ||
98 unsafe.Offsetof(finalizer{}.fn) != 0 ||
99 unsafe.Offsetof(finalizer{}.arg) != sys.PtrSize ||
100 unsafe.Offsetof(finalizer{}.nret) != 2*sys.PtrSize ||
101 unsafe.Offsetof(finalizer{}.fint) != 3*sys.PtrSize ||
102 unsafe.Offsetof(finalizer{}.ot) != 4*sys.PtrSize) {
103 throw("finalizer out of sync")
104 }
105 for i := range finptrmask {
106 finptrmask[i] = finalizer1[i%len(finalizer1)]
107 }
108 }
109 }
110 block := finc
111 finc = block.next
112 block.next = finq
113 finq = block
114 }
115 f := &finq.fin[finq.cnt]
116 atomic.Xadd(&finq.cnt, +1)
117 f.fn = fn
118 f.nret = nret
119 f.fint = fint
120 f.ot = ot
121 f.arg = p
122 fingwake = true
123 unlock(&finlock)
124 }
125
126
127 func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
128 for fb := allfin; fb != nil; fb = fb.alllink {
129 for i := uint32(0); i < fb.cnt; i++ {
130 f := &fb.fin[i]
131 callback(f.fn, f.arg, f.nret, f.fint, f.ot)
132 }
133 }
134 }
135
136 func wakefing() *g {
137 var res *g
138 lock(&finlock)
139 if fingwait && fingwake {
140 fingwait = false
141 fingwake = false
142 res = fing
143 }
144 unlock(&finlock)
145 return res
146 }
147
148 var (
149 fingCreate uint32
150 fingRunning bool
151 )
152
153 func createfing() {
154
155 if fingCreate == 0 && atomic.Cas(&fingCreate, 0, 1) {
156 go runfinq()
157 }
158 }
159
160
161 func runfinq() {
162 var (
163 frame unsafe.Pointer
164 framecap uintptr
165 )
166
167 for {
168 lock(&finlock)
169 fb := finq
170 finq = nil
171 if fb == nil {
172 gp := getg()
173 fing = gp
174 fingwait = true
175 goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
176 continue
177 }
178 unlock(&finlock)
179 if raceenabled {
180 racefingo()
181 }
182 for fb != nil {
183 for i := fb.cnt; i > 0; i-- {
184 f := &fb.fin[i-1]
185
186 framesz := unsafe.Sizeof((interface{})(nil)) + f.nret
187 if framecap < framesz {
188
189
190
191
192 frame = mallocgc(framesz, nil, true)
193 framecap = framesz
194 }
195
196 if f.fint == nil {
197 throw("missing type in runfinq")
198 }
199
200
201
202
203 *(*[2]uintptr)(frame) = [2]uintptr{}
204 switch f.fint.kind & kindMask {
205 case kindPtr:
206
207 *(*unsafe.Pointer)(frame) = f.arg
208 case kindInterface:
209 ityp := (*interfacetype)(unsafe.Pointer(f.fint))
210
211 (*eface)(frame)._type = &f.ot.typ
212 (*eface)(frame).data = f.arg
213 if len(ityp.mhdr) != 0 {
214
215
216 *(*iface)(frame) = assertE2I(ityp, *(*eface)(frame))
217 }
218 default:
219 throw("bad kind in runfinq")
220 }
221 fingRunning = true
222 reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
223 fingRunning = false
224
225
226
227
228
229 f.fn = nil
230 f.arg = nil
231 f.ot = nil
232 atomic.Store(&fb.cnt, i-1)
233 }
234 next := fb.next
235 lock(&finlock)
236 fb.next = finc
237 finc = fb
238 unlock(&finlock)
239 fb = next
240 }
241 }
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309 func SetFinalizer(obj interface{}, finalizer interface{}) {
310 if debug.sbrk != 0 {
311
312
313 return
314 }
315 e := efaceOf(&obj)
316 etyp := e._type
317 if etyp == nil {
318 throw("runtime.SetFinalizer: first argument is nil")
319 }
320 if etyp.kind&kindMask != kindPtr {
321 throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
322 }
323 ot := (*ptrtype)(unsafe.Pointer(etyp))
324 if ot.elem == nil {
325 throw("nil elem type!")
326 }
327
328
329 _, base, _ := findObject(e.data)
330
331 if base == nil {
332
333 if e.data == unsafe.Pointer(&zerobase) {
334 return
335 }
336
337
338
339
340
341
342
343
344
345 for datap := &firstmoduledata; datap != nil; datap = datap.next {
346 if datap.noptrdata <= uintptr(e.data) && uintptr(e.data) < datap.enoptrdata ||
347 datap.data <= uintptr(e.data) && uintptr(e.data) < datap.edata ||
348 datap.bss <= uintptr(e.data) && uintptr(e.data) < datap.ebss ||
349 datap.noptrbss <= uintptr(e.data) && uintptr(e.data) < datap.enoptrbss {
350 return
351 }
352 }
353 throw("runtime.SetFinalizer: pointer not in allocated block")
354 }
355
356 if e.data != base {
357
358
359 if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize {
360 throw("runtime.SetFinalizer: pointer not at beginning of allocated block")
361 }
362 }
363
364 f := efaceOf(&finalizer)
365 ftyp := f._type
366 if ftyp == nil {
367
368 systemstack(func() {
369 removefinalizer(e.data)
370 })
371 return
372 }
373
374 if ftyp.kind&kindMask != kindFunc {
375 throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function")
376 }
377 ft := (*functype)(unsafe.Pointer(ftyp))
378 if ft.dotdotdot() {
379 throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
380 }
381 if ft.inCount != 1 {
382 throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
383 }
384 fint := ft.in()[0]
385 switch {
386 case fint == etyp:
387
388 goto okarg
389 case fint.kind&kindMask == kindPtr:
390 if (fint.uncommon() == nil || etyp.uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
391
392
393 goto okarg
394 }
395 case fint.kind&kindMask == kindInterface:
396 ityp := (*interfacetype)(unsafe.Pointer(fint))
397 if len(ityp.mhdr) == 0 {
398
399 goto okarg
400 }
401 if _, ok := assertE2I2(ityp, *efaceOf(&obj)); ok {
402 goto okarg
403 }
404 }
405 throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
406 okarg:
407
408 nret := uintptr(0)
409 for _, t := range ft.out() {
410 nret = round(nret, uintptr(t.align)) + uintptr(t.size)
411 }
412 nret = round(nret, sys.PtrSize)
413
414
415 createfing()
416
417 systemstack(func() {
418 if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
419 throw("runtime.SetFinalizer: finalizer already set")
420 }
421 })
422 }
423
424
425
426
427 func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
428 c := gomcache()
429 c.local_nlookup++
430 if sys.PtrSize == 4 && c.local_nlookup >= 1<<30 {
431
432 lock(&mheap_.lock)
433 purgecachedstats(c)
434 unlock(&mheap_.lock)
435 }
436
437
438 arena_start := mheap_.arena_start
439 arena_used := mheap_.arena_used
440 if uintptr(v) < arena_start || uintptr(v) >= arena_used {
441 return
442 }
443 p := uintptr(v) >> pageShift
444 q := p - arena_start>>pageShift
445 s = mheap_.spans[q]
446 if s == nil {
447 return
448 }
449 x = unsafe.Pointer(s.base())
450
451 if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
452 s = nil
453 x = nil
454 return
455 }
456
457 n = s.elemsize
458 if s.spanclass.sizeclass() != 0 {
459 x = add(x, (uintptr(v)-uintptr(x))/n*n)
460 }
461 return
462 }
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486 func KeepAlive(x interface{}) {
487
488
489
490 if cgoAlwaysFalse {
491 println(x)
492 }
493 }
494
View as plain text