]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/mfinal.go
[dev.garbage] runtime: use s.base() everywhere it makes sense
[gostls13.git] / src / runtime / mfinal.go
1 // Copyright 2009 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
5 // Garbage collector: finalizers and block profiling.
6
7 package runtime
8
9 import (
10         "runtime/internal/atomic"
11         "runtime/internal/sys"
12         "unsafe"
13 )
14
15 type finblock struct {
16         alllink *finblock
17         next    *finblock
18         cnt     int32
19         _       int32
20         fin     [(_FinBlockSize - 2*sys.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
21 }
22
23 var finlock mutex  // protects the following variables
24 var fing *g        // goroutine that runs finalizers
25 var finq *finblock // list of finalizers that are to be executed
26 var finc *finblock // cache of free blocks
27 var finptrmask [_FinBlockSize / sys.PtrSize / 8]byte
28 var fingwait bool
29 var fingwake bool
30 var allfin *finblock // list of all blocks
31
32 // NOTE: Layout known to queuefinalizer.
33 type finalizer struct {
34         fn   *funcval       // function to call
35         arg  unsafe.Pointer // ptr to object
36         nret uintptr        // bytes of return values from fn
37         fint *_type         // type of first argument of fn
38         ot   *ptrtype       // type of ptr to object
39 }
40
41 var finalizer1 = [...]byte{
42         // Each Finalizer is 5 words, ptr ptr INT ptr ptr (INT = uintptr here)
43         // Each byte describes 8 words.
44         // Need 8 Finalizers described by 5 bytes before pattern repeats:
45         //      ptr ptr INT ptr ptr
46         //      ptr ptr INT ptr ptr
47         //      ptr ptr INT ptr ptr
48         //      ptr ptr INT ptr ptr
49         //      ptr ptr INT ptr ptr
50         //      ptr ptr INT ptr ptr
51         //      ptr ptr INT ptr ptr
52         //      ptr ptr INT ptr ptr
53         // aka
54         //
55         //      ptr ptr INT ptr ptr ptr ptr INT
56         //      ptr ptr ptr ptr INT ptr ptr ptr
57         //      ptr INT ptr ptr ptr ptr INT ptr
58         //      ptr ptr ptr INT ptr ptr ptr ptr
59         //      INT ptr ptr ptr ptr INT ptr ptr
60         //
61         // Assumptions about Finalizer layout checked below.
62         1<<0 | 1<<1 | 0<<2 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 0<<7,
63         1<<0 | 1<<1 | 1<<2 | 1<<3 | 0<<4 | 1<<5 | 1<<6 | 1<<7,
64         1<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 | 0<<6 | 1<<7,
65         1<<0 | 1<<1 | 1<<2 | 0<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7,
66         0<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 | 1<<6 | 1<<7,
67 }
68
69 func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
70         lock(&finlock)
71         if finq == nil || finq.cnt == int32(len(finq.fin)) {
72                 if finc == nil {
73                         // Note: write barrier here, assigning to finc, but should be okay.
74                         finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
75                         finc.alllink = allfin
76                         allfin = finc
77                         if finptrmask[0] == 0 {
78                                 // Build pointer mask for Finalizer array in block.
79                                 // Check assumptions made in finalizer1 array above.
80                                 if (unsafe.Sizeof(finalizer{}) != 5*sys.PtrSize ||
81                                         unsafe.Offsetof(finalizer{}.fn) != 0 ||
82                                         unsafe.Offsetof(finalizer{}.arg) != sys.PtrSize ||
83                                         unsafe.Offsetof(finalizer{}.nret) != 2*sys.PtrSize ||
84                                         unsafe.Offsetof(finalizer{}.fint) != 3*sys.PtrSize ||
85                                         unsafe.Offsetof(finalizer{}.ot) != 4*sys.PtrSize) {
86                                         throw("finalizer out of sync")
87                                 }
88                                 for i := range finptrmask {
89                                         finptrmask[i] = finalizer1[i%len(finalizer1)]
90                                 }
91                         }
92                 }
93                 block := finc
94                 finc = block.next
95                 block.next = finq
96                 finq = block
97         }
98         f := &finq.fin[finq.cnt]
99         finq.cnt++
100         f.fn = fn
101         f.nret = nret
102         f.fint = fint
103         f.ot = ot
104         f.arg = p
105         fingwake = true
106         unlock(&finlock)
107 }
108
109 //go:nowritebarrier
110 func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
111         for fb := allfin; fb != nil; fb = fb.alllink {
112                 for i := int32(0); i < fb.cnt; i++ {
113                         f := &fb.fin[i]
114                         callback(f.fn, f.arg, f.nret, f.fint, f.ot)
115                 }
116         }
117 }
118
119 func wakefing() *g {
120         var res *g
121         lock(&finlock)
122         if fingwait && fingwake {
123                 fingwait = false
124                 fingwake = false
125                 res = fing
126         }
127         unlock(&finlock)
128         return res
129 }
130
131 var (
132         fingCreate  uint32
133         fingRunning bool
134 )
135
136 func createfing() {
137         // start the finalizer goroutine exactly once
138         if fingCreate == 0 && atomic.Cas(&fingCreate, 0, 1) {
139                 go runfinq()
140         }
141 }
142
143 // This is the goroutine that runs all of the finalizers
144 func runfinq() {
145         var (
146                 frame    unsafe.Pointer
147                 framecap uintptr
148         )
149
150         for {
151                 lock(&finlock)
152                 fb := finq
153                 finq = nil
154                 if fb == nil {
155                         gp := getg()
156                         fing = gp
157                         fingwait = true
158                         goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
159                         continue
160                 }
161                 unlock(&finlock)
162                 if raceenabled {
163                         racefingo()
164                 }
165                 for fb != nil {
166                         for i := fb.cnt; i > 0; i-- {
167                                 f := &fb.fin[i-1]
168
169                                 framesz := unsafe.Sizeof((interface{})(nil)) + f.nret
170                                 if framecap < framesz {
171                                         // The frame does not contain pointers interesting for GC,
172                                         // all not yet finalized objects are stored in finq.
173                                         // If we do not mark it as FlagNoScan,
174                                         // the last finalized object is not collected.
175                                         frame = mallocgc(framesz, nil, true)
176                                         framecap = framesz
177                                 }
178
179                                 if f.fint == nil {
180                                         throw("missing type in runfinq")
181                                 }
182                                 switch f.fint.kind & kindMask {
183                                 case kindPtr:
184                                         // direct use of pointer
185                                         *(*unsafe.Pointer)(frame) = f.arg
186                                 case kindInterface:
187                                         ityp := (*interfacetype)(unsafe.Pointer(f.fint))
188                                         // set up with empty interface
189                                         (*eface)(frame)._type = &f.ot.typ
190                                         (*eface)(frame).data = f.arg
191                                         if len(ityp.mhdr) != 0 {
192                                                 // convert to interface with methods
193                                                 // this conversion is guaranteed to succeed - we checked in SetFinalizer
194                                                 assertE2I(ityp, *(*eface)(frame), (*iface)(frame))
195                                         }
196                                 default:
197                                         throw("bad kind in runfinq")
198                                 }
199                                 fingRunning = true
200                                 reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
201                                 fingRunning = false
202
203                                 // drop finalizer queue references to finalized object
204                                 f.fn = nil
205                                 f.arg = nil
206                                 f.ot = nil
207                                 fb.cnt = i - 1
208                         }
209                         next := fb.next
210                         lock(&finlock)
211                         fb.next = finc
212                         finc = fb
213                         unlock(&finlock)
214                         fb = next
215                 }
216         }
217 }
218
219 // SetFinalizer sets the finalizer associated with obj to the provided
220 // finalizer function. When the garbage collector finds an unreachable block
221 // with an associated finalizer, it clears the association and runs
222 // finalizer(obj) in a separate goroutine. This makes obj reachable again,
223 // but now without an associated finalizer. Assuming that SetFinalizer
224 // is not called again, the next time the garbage collector sees
225 // that obj is unreachable, it will free obj.
226 //
227 // SetFinalizer(obj, nil) clears any finalizer associated with obj.
228 //
229 // The argument obj must be a pointer to an object allocated by
230 // calling new or by taking the address of a composite literal.
231 // The argument finalizer must be a function that takes a single argument
232 // to which obj's type can be assigned, and can have arbitrary ignored return
233 // values. If either of these is not true, SetFinalizer aborts the
234 // program.
235 //
236 // Finalizers are run in dependency order: if A points at B, both have
237 // finalizers, and they are otherwise unreachable, only the finalizer
238 // for A runs; once A is freed, the finalizer for B can run.
239 // If a cyclic structure includes a block with a finalizer, that
240 // cycle is not guaranteed to be garbage collected and the finalizer
241 // is not guaranteed to run, because there is no ordering that
242 // respects the dependencies.
243 //
244 // The finalizer for obj is scheduled to run at some arbitrary time after
245 // obj becomes unreachable.
246 // There is no guarantee that finalizers will run before a program exits,
247 // so typically they are useful only for releasing non-memory resources
248 // associated with an object during a long-running program.
249 // For example, an os.File object could use a finalizer to close the
250 // associated operating system file descriptor when a program discards
251 // an os.File without calling Close, but it would be a mistake
252 // to depend on a finalizer to flush an in-memory I/O buffer such as a
253 // bufio.Writer, because the buffer would not be flushed at program exit.
254 //
255 // It is not guaranteed that a finalizer will run if the size of *obj is
256 // zero bytes.
257 //
258 // It is not guaranteed that a finalizer will run for objects allocated
259 // in initializers for package-level variables. Such objects may be
260 // linker-allocated, not heap-allocated.
261 //
262 // A single goroutine runs all finalizers for a program, sequentially.
263 // If a finalizer must run for a long time, it should do so by starting
264 // a new goroutine.
265 func SetFinalizer(obj interface{}, finalizer interface{}) {
266         if debug.sbrk != 0 {
267                 // debug.sbrk never frees memory, so no finalizers run
268                 // (and we don't have the data structures to record them).
269                 return
270         }
271         e := efaceOf(&obj)
272         etyp := e._type
273         if etyp == nil {
274                 throw("runtime.SetFinalizer: first argument is nil")
275         }
276         if etyp.kind&kindMask != kindPtr {
277                 throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
278         }
279         ot := (*ptrtype)(unsafe.Pointer(etyp))
280         if ot.elem == nil {
281                 throw("nil elem type!")
282         }
283
284         // find the containing object
285         _, base, _ := findObject(e.data)
286
287         if base == nil {
288                 // 0-length objects are okay.
289                 if e.data == unsafe.Pointer(&zerobase) {
290                         return
291                 }
292
293                 // Global initializers might be linker-allocated.
294                 //      var Foo = &Object{}
295                 //      func main() {
296                 //              runtime.SetFinalizer(Foo, nil)
297                 //      }
298                 // The relevant segments are: noptrdata, data, bss, noptrbss.
299                 // We cannot assume they are in any order or even contiguous,
300                 // due to external linking.
301                 for datap := &firstmoduledata; datap != nil; datap = datap.next {
302                         if datap.noptrdata <= uintptr(e.data) && uintptr(e.data) < datap.enoptrdata ||
303                                 datap.data <= uintptr(e.data) && uintptr(e.data) < datap.edata ||
304                                 datap.bss <= uintptr(e.data) && uintptr(e.data) < datap.ebss ||
305                                 datap.noptrbss <= uintptr(e.data) && uintptr(e.data) < datap.enoptrbss {
306                                 return
307                         }
308                 }
309                 throw("runtime.SetFinalizer: pointer not in allocated block")
310         }
311
312         if e.data != base {
313                 // As an implementation detail we allow to set finalizers for an inner byte
314                 // of an object if it could come from tiny alloc (see mallocgc for details).
315                 if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize {
316                         throw("runtime.SetFinalizer: pointer not at beginning of allocated block")
317                 }
318         }
319
320         f := efaceOf(&finalizer)
321         ftyp := f._type
322         if ftyp == nil {
323                 // switch to system stack and remove finalizer
324                 systemstack(func() {
325                         removefinalizer(e.data)
326                 })
327                 return
328         }
329
330         if ftyp.kind&kindMask != kindFunc {
331                 throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function")
332         }
333         ft := (*functype)(unsafe.Pointer(ftyp))
334         if ft.dotdotdot() {
335                 throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
336         }
337         if ft.dotdotdot() || ft.inCount != 1 {
338                 throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
339         }
340         fint := ft.in()[0]
341         switch {
342         case fint == etyp:
343                 // ok - same type
344                 goto okarg
345         case fint.kind&kindMask == kindPtr:
346                 if (fint.uncommon() == nil || etyp.uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
347                         // ok - not same type, but both pointers,
348                         // one or the other is unnamed, and same element type, so assignable.
349                         goto okarg
350                 }
351         case fint.kind&kindMask == kindInterface:
352                 ityp := (*interfacetype)(unsafe.Pointer(fint))
353                 if len(ityp.mhdr) == 0 {
354                         // ok - satisfies empty interface
355                         goto okarg
356                 }
357                 if assertE2I2(ityp, *efaceOf(&obj), nil) {
358                         goto okarg
359                 }
360         }
361         throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
362 okarg:
363         // compute size needed for return parameters
364         nret := uintptr(0)
365         for _, t := range ft.out() {
366                 nret = round(nret, uintptr(t.align)) + uintptr(t.size)
367         }
368         nret = round(nret, sys.PtrSize)
369
370         // make sure we have a finalizer goroutine
371         createfing()
372
373         systemstack(func() {
374                 if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
375                         throw("runtime.SetFinalizer: finalizer already set")
376                 }
377         })
378 }
379
380 // Look up pointer v in heap. Return the span containing the object,
381 // the start of the object, and the size of the object. If the object
382 // does not exist, return nil, nil, 0.
383 func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
384         c := gomcache()
385         c.local_nlookup++
386         if sys.PtrSize == 4 && c.local_nlookup >= 1<<30 {
387                 // purge cache stats to prevent overflow
388                 lock(&mheap_.lock)
389                 purgecachedstats(c)
390                 unlock(&mheap_.lock)
391         }
392
393         // find span
394         arena_start := mheap_.arena_start
395         arena_used := mheap_.arena_used
396         if uintptr(v) < arena_start || uintptr(v) >= arena_used {
397                 return
398         }
399         p := uintptr(v) >> pageShift
400         q := p - arena_start>>pageShift
401         s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*sys.PtrSize))
402         if s == nil {
403                 return
404         }
405         x = unsafe.Pointer(s.base())
406
407         if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
408                 s = nil
409                 x = nil
410                 return
411         }
412
413         n = s.elemsize
414         if s.sizeclass != 0 {
415                 x = add(x, (uintptr(v)-uintptr(x))/n*n)
416         }
417         return
418 }