}
checker := new(netTokenChecker)
- runtime.SetFinalizer(checker, (*netTokenChecker).panicUnreleased)
+ cleanup := runtime.AddCleanup(checker, func(_ int) { panic("internal error: net token acquired but not released") }, 0)
return func() {
if checker.released {
if hasToken {
<-netLimitSem
}
- runtime.SetFinalizer(checker, nil)
+ cleanup.Stop()
}, nil
}
// “tiny allocator”.
unusedAvoidTinyAllocator string
}
-
-func (c *netTokenChecker) panicUnreleased() {
- panic("internal error: net token acquired but not released")
-}
type File struct {
osFile
closed bool
+ // cleanup panics when the file is no longer referenced and it has not been closed.
+ cleanup runtime.Cleanup
}
// osFile embeds a *os.File while keeping the pointer itself unexported.
// Although the operating system will drop locks for open files when the go
// command exits, we want to hold locks for as little time as possible, and we
// especially don't want to leave a file locked after we're done with it. Our
- // Close method is what releases the locks, so use a finalizer to report
+ // Close method is what releases the locks, so use a cleanup to report
// missing Close calls on a best-effort basis.
- runtime.SetFinalizer(f, func(f *File) {
- panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", f.Name()))
- })
+ f.cleanup = runtime.AddCleanup(f, func(fileName string) {
+ panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", fileName))
+ }, f.Name())
return f, nil
}
f.closed = true
err := closeFile(f.osFile.File)
- runtime.SetFinalizer(f, nil)
+ f.cleanup.Stop()
return err
}