diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-09 22:18:42 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-09 22:18:42 +0300 |
| commit | 7031211501884555139351bb676fc0592c9df14c (patch) | |
| tree | dc5bf201bacb706c355f477413ad375a6d8fbe5b /internal/event | |
| parent | bab929022f4f4bba77439c63d130c833595758b6 (diff) | |
feat(parquet): surface epoll_ctl op/target-fd/events metadata
epoll_ctl's BPF handler already decodes the operation (args[1]),
target descriptor (args[2]), and requested event mask (args[3]->events)
into an EpollCtlEvent, but the single resolved-epfd `fd` column was the
only epoll detail reaching the output schema. Consumers could not see
which descriptor was registered nor the operation performed.
Surface the metadata as three additive, backward-compatible columns,
mirroring the existing dedicated optional-column convention used by
requested_sleep_ns and address_space_bytes:
- epoll_op (String): ADD/MOD/DEL, or the raw decimal for unknown ops;
empty for non-epoll_ctl rows.
- epoll_target_fd (Int32): registered descriptor (args[2]); 0 otherwise.
- epoll_events (UInt32): requested event mask; 0 otherwise.
Data flows EpollCtlEvent -> event.Pair (new EpollCtl/HasEpoll fields,
populated in handleEpollCtlExit) -> streamrow.Row -> parquet.Record.
The op-to-string mapping lives on event.EpollCtl.OpName.
Docs (docs/parquet-querying.md) and the Magefile parquetValidate column
list updated in lockstep (also adding the previously-undocumented
address_space_bytes/requested_sleep_ns columns). The polling parquet
integration test now asserts epoll_ctl rows carry a decoded op and a
valid target fd, and that other syscalls leave epoll_op empty.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/event')
| -rw-r--r-- | internal/event/pair.go | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/internal/event/pair.go b/internal/event/pair.go index 523f961..afc9bed 100644 --- a/internal/event/pair.go +++ b/internal/event/pair.go @@ -31,6 +31,44 @@ type Pair struct { AddressSpaceBytes uint64 // RequestedSleepNs tracks requested sleep duration for nanosleep-style syscalls. RequestedSleepNs int64 + // Epoll carries epoll_ctl control metadata (op, target fd, requested event + // mask). It is only populated for epoll_ctl pairs; HasEpoll reports whether + // it is set. The Pair-level File still resolves to the epoll instance (epfd); + // Epoll.TargetFD is the descriptor being registered/modified/removed. + Epoll EpollCtl + HasEpoll bool +} + +// EpollCtl holds the decoded epoll_ctl arguments surfaced from the BPF +// EpollCtlEvent: the operation (EPOLL_CTL_ADD/MOD/DEL), the target fd +// (args[2]), and the requested epoll event mask (args[3]->events). +type EpollCtl struct { + Op int32 + TargetFD int32 + Events uint32 +} + +// Linux epoll_ctl op values from <sys/epoll.h>. +const ( + epollCtlAdd = 1 + epollCtlDel = 2 + epollCtlMod = 3 +) + +// OpName renders the epoll_ctl operation as a human-readable token +// (ADD/DEL/MOD). Unknown values fall back to their decimal form so the +// raw op is never lost. +func (c EpollCtl) OpName() string { + switch c.Op { + case epollCtlAdd: + return "ADD" + case epollCtlDel: + return "DEL" + case epollCtlMod: + return "MOD" + default: + return strconv.FormatInt(int64(c.Op), 10) + } } func NewPair(enterEv Event) *Pair { |
