From 96065ab5c13295f0c2ec810cf540c229c41e2647 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Mon, 1 Jun 2026 11:14:53 +0300 Subject: test(integration): add Signals family tracing coverage The SIGNALS syscall family previously had zero end-to-end coverage (signalfd/signalfd4 are IPC-family fd creators, not Signals). Add a self-targeting ioworkload scenario and an integration test that assert the family's tracepoints fire. scenario_signals.go (signals-basic) issues, all self-directed so it mutates no other process: - rt_sigaction : install SIG_IGN disposition for SIGUSR1 - rt_sigprocmask: BLOCK SIGUSR1 before sending, so self-delivery only marks it pending (never runs a handler / kills us) - sigaltstack : set then disable an alternate signal stack - kill/tgkill/tkill/rt_sigqueueinfo: send SIGUSR1 to self four ways - rt_sigpending : query the pending mask - rt_sigtimedwait: reap the pending signal with a SHORT 100ms timeout (hang guard); EAGAIN tolerated Safety: signal is blocked before any send; rt_sigtimedwait uses a 100ms timeout so it cannot hang; the original signal mask and SIGUSR1 disposition are restored and the alt stack disabled on exit. The goroutine is pinned with LockOSThread so gettid() matches the tgkill/tkill target and the per-thread mask applies to the waiting thread. Raw syscalls are issued directly so the tracepoints fire regardless of the Go runtime's own signal handling. pause (noreturn) and rt_sigreturn (handler-return only) are deliberately excluded. signals_test.go asserts enter_ tracepoints with MinCount>=1 for rt_sigaction, rt_sigprocmask, rt_sigpending, sigaltstack, kill, tgkill, and rt_sigtimedwait, plus a positive duration for the rt_sigtimedwait enter/exit pair. Co-Authored-By: Claude Opus 4.8 --- integrationtests/signals_test.go | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 integrationtests/signals_test.go (limited to 'integrationtests') diff --git a/integrationtests/signals_test.go b/integrationtests/signals_test.go new file mode 100644 index 0000000..98840aa --- /dev/null +++ b/integrationtests/signals_test.go @@ -0,0 +1,42 @@ +package integrationtests + +import "testing" + +// signalsTraceArgs restricts tracing to the SIGNALS-family syscalls the +// signals-basic workload issues, so the output is dominated by those calls. +// pause (noreturn-blocking) and rt_sigreturn (only reachable via handler +// return) are intentionally absent: the scenario never invokes them. +var signalsTraceArgs = []string{ + "-trace-syscalls", + "rt_sigaction,rt_sigprocmask,rt_sigpending,sigaltstack,kill,tgkill,tkill,rt_sigqueueinfo,rt_sigtimedwait", +} + +// TestSignalsBasic verifies the SIGNALS syscall family is traced end-to-end. +// The signals-basic workload self-directs every call (installs a handler, +// blocks SIGUSR1, sets an alternate stack, sends SIGUSR1 to itself four ways, +// queries pending signals, and reaps one with a short timeout), so it never +// touches another process. Each required syscall must appear as an enter event. +func TestSignalsBasic(t *testing.T) { + h := newTestHarness(t) + result, pid, err := h.RunWithIorArgs("signals-basic", defaultDuration, signalsTraceArgs) + if err != nil { + t.Fatalf("run scenario signals-basic: %v", err) + } + + AssertNoUnexpectedPID(t, result, pid) + AssertNoUnexpectedComm(t, result, "ioworkload") + AssertEventsPresent(t, result, []ExpectedEvent{ + {Tracepoint: "enter_rt_sigaction", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_rt_sigprocmask", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_rt_sigpending", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_sigaltstack", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_kill", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_tgkill", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_rt_sigtimedwait", Comm: "ioworkload", MinCount: 1}, + }) + + // rt_sigtimedwait blocks (briefly) on its timeout, so the paired enter/exit + // must carry a positive duration — proof the exit tracepoint was correlated. + assertEventDurationPositive(t, result, + ExpectedEvent{Tracepoint: "enter_rt_sigtimedwait", Comm: "ioworkload"}) +} -- cgit v1.2.3