![dependabot[bot]](/assets/img/avatar_default.png)
Bumps [github.com/containerd/cgroups/v3](https://github.com/containerd/cgroups) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/containerd/cgroups/releases) - [Commits](https://github.com/containerd/cgroups/compare/v3.0.2...v3.0.3) --- updated-dependencies: - dependency-name: github.com/containerd/cgroups/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package sys
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"runtime"
|
|
"sync"
|
|
)
|
|
|
|
// OnLeakFD controls tracing [FD] lifetime to detect resources that are not
|
|
// closed by Close().
|
|
//
|
|
// If fn is not nil, tracing is enabled for all FDs created going forward. fn is
|
|
// invoked for all FDs that are closed by the garbage collector instead of an
|
|
// explicit Close() by a caller. Calling OnLeakFD twice with a non-nil fn
|
|
// (without disabling tracing in the meantime) will cause a panic.
|
|
//
|
|
// If fn is nil, tracing will be disabled. Any FDs that have not been closed are
|
|
// considered to be leaked, fn will be invoked for them, and the process will be
|
|
// terminated.
|
|
//
|
|
// fn will be invoked at most once for every unique sys.FD allocation since a
|
|
// runtime.Frames can only be unwound once.
|
|
func OnLeakFD(fn func(*runtime.Frames)) {
|
|
// Enable leak tracing if new fn is provided.
|
|
if fn != nil {
|
|
if onLeakFD != nil {
|
|
panic("OnLeakFD called twice with non-nil fn")
|
|
}
|
|
|
|
onLeakFD = fn
|
|
return
|
|
}
|
|
|
|
// fn is nil past this point.
|
|
|
|
if onLeakFD == nil {
|
|
return
|
|
}
|
|
|
|
// Call onLeakFD for all open fds.
|
|
if fs := flushFrames(); len(fs) != 0 {
|
|
for _, f := range fs {
|
|
onLeakFD(f)
|
|
}
|
|
}
|
|
|
|
onLeakFD = nil
|
|
}
|
|
|
|
var onLeakFD func(*runtime.Frames)
|
|
|
|
// fds is a registry of all file descriptors wrapped into sys.fds that were
|
|
// created while an fd tracer was active.
|
|
var fds sync.Map // map[int]*runtime.Frames
|
|
|
|
// flushFrames removes all elements from fds and returns them as a slice. This
|
|
// deals with the fact that a runtime.Frames can only be unwound once using
|
|
// Next().
|
|
func flushFrames() []*runtime.Frames {
|
|
var frames []*runtime.Frames
|
|
fds.Range(func(key, value any) bool {
|
|
frames = append(frames, value.(*runtime.Frames))
|
|
fds.Delete(key)
|
|
return true
|
|
})
|
|
return frames
|
|
}
|
|
|
|
func callersFrames() *runtime.Frames {
|
|
c := make([]uintptr, 32)
|
|
|
|
// Skip runtime.Callers and this function.
|
|
i := runtime.Callers(2, c)
|
|
if i == 0 {
|
|
return nil
|
|
}
|
|
|
|
return runtime.CallersFrames(c)
|
|
}
|
|
|
|
// FormatFrames formats a runtime.Frames as a human-readable string.
|
|
func FormatFrames(fs *runtime.Frames) string {
|
|
var b bytes.Buffer
|
|
for {
|
|
f, more := fs.Next()
|
|
b.WriteString(fmt.Sprintf("\t%s+%#x\n\t\t%s:%d\n", f.Function, f.PC-f.Entry, f.File, f.Line))
|
|
if !more {
|
|
break
|
|
}
|
|
}
|
|
return b.String()
|
|
}
|