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