summaryrefslogtreecommitdiff
path: root/internal/ior_bpfsetup.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-13 19:38:09 +0300
committerPaul Buetow <paul@buetow.org>2026-05-13 19:38:09 +0300
commit7b4f74ab11a2504d107372afebdfd77dec59ea42 (patch)
tree5da7edf16a764442e3acee16bc68965b04c98727 /internal/ior_bpfsetup.go
parentf4a814df4e39ff5547a88d4f5d37ae6fe159cc76 (diff)
fix: stop BPF ring-buffer polling goroutine on trace end to prevent leak
setupEventChannel now returns the *bpf.RingBuffer handle alongside the event channel. Both callers (runTraceWithContext, runHeadlessParquet) defer rb.Stop() so the libbpfgo polling goroutine and C ring_buffer struct are released promptly when the trace context is cancelled, rather than waiting for bpfModule.Close() to eventually call rb.Close(). rb.Stop() and rb.Close() are both idempotent, so the double-call from the defer and from bpfModule.Close() is safe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/ior_bpfsetup.go')
-rw-r--r--internal/ior_bpfsetup.go13
1 files changed, 9 insertions, 4 deletions
diff --git a/internal/ior_bpfsetup.go b/internal/ior_bpfsetup.go
index 0d32d4c..61009c6 100644
--- a/internal/ior_bpfsetup.go
+++ b/internal/ior_bpfsetup.go
@@ -87,15 +87,20 @@ func setupBPFModule(parentCtx context.Context, cfg flags.Config) (*bpf.Module, *
return bpfModule, mgr, releaseBindings, nil
}
-// setupEventChannel initialises the BPF ring-buffer and returns the event channel.
-func setupEventChannel(bpfModule *bpf.Module) (chan []byte, error) {
+// setupEventChannel initialises the BPF ring-buffer and returns both the event
+// channel and the ring-buffer handle. The caller must call rb.Stop() when the
+// trace ends (before bpfModule.Close()) to promptly halt the background polling
+// goroutine and release the C ring_buffer struct. bpfModule.Close() also closes
+// all ring buffers it owns, but only calling Stop() first ensures the goroutine
+// exits without waiting for the module teardown path.
+func setupEventChannel(bpfModule *bpf.Module) (chan []byte, *bpf.RingBuffer, error) {
ch := make(chan []byte, appconfig.DefaultChannelBufferSize)
rb, err := bpfModule.InitRingBuf("event_map", ch)
if err != nil {
- return nil, err
+ return nil, nil, err
}
rb.Poll(300)
- return ch, nil
+ return ch, rb, nil
}
// --- compile-time interface satisfaction assertions ---