From f0aefa625b5b0d0b3612cfba9bd25c825a71818f Mon Sep 17 00:00:00 2001 From: Pat Tullmann Date: Tue, 22 Apr 2025 09:31:14 -0700 Subject: posix: remove empty_sigset When linking a libc, Zig should defer to the C library for sigset operations. The pre-filled constants signal sets (empty_sigset, filled_sigset) are not compatible with C library initialization, so remove them and use the runtime `sigemptyset` and `sigfillset` methods to initialize any sigset. --- lib/std/debug.zig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d2b17ed30d..c0b360fda3 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1389,9 +1389,10 @@ pub fn attachSegfaultHandler() void { } var act = posix.Sigaction{ .handler = .{ .sigaction = handleSegfaultPosix }, - .mask = posix.empty_sigset, + .mask = undefined, .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND), }; + posix.sigemptyset(&act.mask); updateSegfaultHandler(&act); } @@ -1406,9 +1407,10 @@ fn resetSegfaultHandler() void { } var act = posix.Sigaction{ .handler = .{ .handler = posix.SIG.DFL }, - .mask = posix.empty_sigset, + .mask = undefined, .flags = 0, }; + posix.sigemptyset(&act.mask); updateSegfaultHandler(&act); } -- cgit v1.2.3 From 120c4789c31c066f15fe414a5b32cdc7e80a065c Mon Sep 17 00:00:00 2001 From: Pat Tullmann Date: Tue, 22 Apr 2025 14:19:06 -0700 Subject: sigset_t: sigemptyset() and sigfillset() are functions that return sigset_t By returning an initialized sigset (instead of taking the set as an output parameter), these functions can be used to directly initialize the `mask` parameter of a `Sigaction` instance. --- lib/std/Progress.zig | 5 ++--- lib/std/debug.zig | 11 ++++------- lib/std/os/emscripten.zig | 4 +++- lib/std/os/linux.zig | 12 ++++++++---- lib/std/os/linux/test.zig | 12 +++++------- lib/std/os/plan9.zig | 5 ++++- lib/std/posix.zig | 29 +++++++++++++++++------------ lib/std/posix/test.zig | 35 ++++++++++++++++------------------- lib/std/start.zig | 5 ++--- src/crash_report.zig | 5 ++--- test/standalone/sigpipe/build.zig | 5 ++--- 11 files changed, 65 insertions(+), 63 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index 3e5f29c54e..2213bd9b11 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -410,12 +410,11 @@ pub fn start(options: Options) Node { } if (have_sigwinch) { - var act: posix.Sigaction = .{ + const act: posix.Sigaction = .{ .handler = .{ .sigaction = handleSigWinch }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = (posix.SA.SIGINFO | posix.SA.RESTART), }; - posix.sigemptyset(&act.mask); posix.sigaction(posix.SIG.WINCH, &act, null); } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index c0b360fda3..eb7cf793f2 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1387,13 +1387,11 @@ pub fn attachSegfaultHandler() void { windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); return; } - var act = posix.Sigaction{ + const act = posix.Sigaction{ .handler = .{ .sigaction = handleSegfaultPosix }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND), }; - posix.sigemptyset(&act.mask); - updateSegfaultHandler(&act); } @@ -1405,12 +1403,11 @@ fn resetSegfaultHandler() void { } return; } - var act = posix.Sigaction{ + const act = posix.Sigaction{ .handler = .{ .handler = posix.SIG.DFL }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = 0, }; - posix.sigemptyset(&act.mask); updateSegfaultHandler(&act); } diff --git a/lib/std/os/emscripten.zig b/lib/std/os/emscripten.zig index ad7a3f65c1..0e07a8afb7 100644 --- a/lib/std/os/emscripten.zig +++ b/lib/std/os/emscripten.zig @@ -560,7 +560,9 @@ pub const Sigaction = extern struct { }; pub const sigset_t = [1024 / 32]u32; -pub const empty_sigset = [_]u32{0} ** @typeInfo(sigset_t).array.len; +pub fn sigemptyset() sigset_t { + return [_]u32{0} ** @typeInfo(sigset_t).array.len; +} pub const siginfo_t = extern struct { signo: i32, errno: i32, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 3e5c808f56..ee44bf072b 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1800,11 +1800,15 @@ const SigsetElement = c_ulong; const sigset_len = @typeInfo(sigset_t).array.len; -/// Empty set to initialize sigset_t instances from. No need for `sigemptyset`. -pub const empty_sigset: sigset_t = [_]SigsetElement{0} ** sigset_len; +/// Zig's version of sigemptyset. Returns initialized sigset_t. +pub fn sigemptyset() sigset_t { + return [_]SigsetElement{0} ** sigset_len; +} -/// Filled set to initialize sigset_t instances from. No need for `sigfillset`. -pub const filled_sigset: sigset_t = [_]SigsetElement{~@as(SigsetElement, 0)} ** sigset_len; +/// Zig's version of sigfillset. Returns initalized sigset_t. +pub fn sigfillset() sigset_t { + return [_]SigsetElement{~@as(SigsetElement, 0)} ** sigset_len; +} fn sigset_bit_index(sig: usize) struct { word: usize, mask: SigsetElement } { assert(sig > 0); diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index 097c5a388c..7f5deff480 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -128,7 +128,7 @@ test "fadvise" { test "sigset_t" { std.debug.assert(@sizeOf(linux.sigset_t) == (linux.NSIG / 8)); - var sigset = linux.empty_sigset; + var sigset = linux.sigemptyset(); // See that none are set, then set each one, see that they're all set, then // remove them all, and then see that none are set. @@ -140,8 +140,6 @@ test "sigset_t" { } for (1..linux.NSIG) |i| { try expectEqual(linux.sigismember(&sigset, @truncate(i)), true); - try expectEqual(linux.sigismember(&linux.filled_sigset, @truncate(i)), true); - try expectEqual(linux.sigismember(&linux.empty_sigset, @truncate(i)), false); } for (1..linux.NSIG) |i| { linux.sigdelset(&sigset, @truncate(i)); @@ -183,16 +181,16 @@ test "sigset_t" { } } -test "filled_sigset" { +test "sigfillset" { // unlike the C library, all the signals are set in the kernel-level fillset - const sigset = linux.filled_sigset; + const sigset = linux.sigfillset(); for (1..linux.NSIG) |i| { try expectEqual(linux.sigismember(&sigset, @truncate(i)), true); } } -test "empty_sigset" { - const sigset = linux.empty_sigset; +test "sigemptyset" { + const sigset = linux.sigemptyset(); for (1..linux.NSIG) |i| { try expectEqual(linux.sigismember(&sigset, @truncate(i)), false); } diff --git a/lib/std/os/plan9.zig b/lib/std/os/plan9.zig index 1882eda476..b910e26c71 100644 --- a/lib/std/os/plan9.zig +++ b/lib/std/os/plan9.zig @@ -182,7 +182,6 @@ pub const SIG = struct { pub const TTOU = 20; }; pub const sigset_t = c_long; -pub const empty_sigset = 0; pub const siginfo_t = c_long; // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we include it here to be compatible. pub const Sigaction = extern struct { @@ -199,6 +198,10 @@ pub const Sigaction = extern struct { pub const AT = struct { pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9 }; +// Plan 9 doesn't do signals. This is just needed to get through start.zig. +pub fn sigemptyset() sigset_t { + return 0; +} // TODO implement sigaction // right now it is just a shim to allow using start.zig code pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize { diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 1113224da8..f414aa801b 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -677,7 +677,8 @@ pub fn abort() noreturn { raise(SIG.ABRT) catch {}; // Disable all signal handlers. - sigprocmask(SIG.BLOCK, &linux.filled_sigset, null); + const filledset = linux.sigfillset(); + sigprocmask(SIG.BLOCK, &filledset, null); // Only one thread may proceed to the rest of abort(). if (!builtin.single_threaded) { @@ -690,14 +691,14 @@ pub fn abort() noreturn { // Install default handler so that the tkill below will terminate. const sigact = Sigaction{ .handler = .{ .handler = SIG.DFL }, - .mask = linux.empty_sigset, + .mask = sigemptyset(), .flags = 0, }; sigaction(SIG.ABRT, &sigact, null); _ = linux.tkill(linux.gettid(), SIG.ABRT); - var sigabrtmask = linux.empty_sigset; + var sigabrtmask = sigemptyset(); sigaddset(&sigabrtmask, SIG.ABRT); sigprocmask(SIG.UNBLOCK, &sigabrtmask, null); @@ -727,7 +728,7 @@ pub fn raise(sig: u8) RaiseError!void { // cannot trigger an extra, unexpected, inter-process signal. Signal paranoia inherited from Musl. const filled = linux.sigfillset(); var orig: sigset_t = undefined; - sigprocmask(SIG.BLOCK, &linux.filled_sigset, &orig); + sigprocmask(SIG.BLOCK, &filled, &orig); const rc = linux.tkill(linux.gettid(), sig); sigprocmask(SIG.SETMASK, &orig, null); @@ -5813,24 +5814,28 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { } } -pub fn sigfillset(set: *sigset_t) void { +/// Return a filled sigset_t. +pub fn sigfillset() sigset_t { if (builtin.link_libc) { - switch (errno(system.sigfillset(set))) { - .SUCCESS => return, + var set: sigset_t = undefined; + switch (errno(system.sigfillset(&set))) { + .SUCCESS => return set, else => unreachable, } } - set.* = system.filled_sigset; + return system.sigfillset(); } -pub fn sigemptyset(set: *sigset_t) void { +/// Return an empty sigset_t. +pub fn sigemptyset() sigset_t { if (builtin.link_libc) { - switch (errno(system.sigemptyset(set))) { - .SUCCESS => return, + var set: sigset_t = undefined; + switch (errno(system.sigemptyset(&set))) { + .SUCCESS => return set, else => unreachable, } } - set.* = mem.zeroes(sigset_t); + return system.sigemptyset(); } pub fn sigaddset(set: *sigset_t, sig: u8) void { diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 7be60be88d..c886ed6153 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -863,17 +863,15 @@ test "sigset empty/full" { if (native_os == .wasi or native_os == .windows) return error.SkipZigTest; - var set: posix.sigset_t = undefined; - - posix.sigemptyset(&set); + var set: posix.sigset_t = posix.sigemptyset(); for (1..posix.NSIG) |i| { try expectEqual(false, posix.sigismember(&set, @truncate(i))); } // The C library can reserve some (unnamed) signals, so can't check the full // NSIG set is defined, but just test a couple: - posix.sigfillset(&set); - try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.USR1))); + set = posix.sigfillset(); + try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.CHLD))); try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT))); } @@ -887,8 +885,7 @@ test "sigset add/del" { if (native_os == .wasi or native_os == .windows) return error.SkipZigTest; - var sigset: posix.sigset_t = undefined; - posix.sigemptyset(&sigset); + var sigset: posix.sigset_t = posix.sigemptyset(); // See that none are set, then set each one, see that they're all set, then // remove them all, and then see that none are set. @@ -924,7 +921,7 @@ test "sigaction" { return error.SkipZigTest; } - const test_signo = posix.SIG.USR1; + const test_signo = posix.SIG.URG; // URG only because it is ignored by default in debuggers const S = struct { var handler_called_count: u32 = 0; @@ -944,10 +941,10 @@ test "sigaction" { var sa: posix.Sigaction = .{ .handler = .{ .sigaction = &S.handler }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = posix.SA.SIGINFO | posix.SA.RESETHAND, }; - posix.sigemptyset(&sa.mask); + var old_sa: posix.Sigaction = undefined; // Install the new signal handler. @@ -1009,29 +1006,29 @@ test "sigset_t bits" { const self_pid = posix.system.getpid(); - // To check that sigset_t mapping matches kernel (think u32/u64 - // mismatches on big-endian), try sending a blocked signal to make - // sure the mask matches the signal. - inline for ([_]usize{ posix.SIG.INT, posix.SIG.USR1, 62, 94, 126 }) |test_signo| { + // To check that sigset_t mapping matches kernel (think u32/u64 mismatches on + // big-endian), try sending a blocked signal to make sure the mask matches the + // signal. (Send URG and CHLD because they're ignored by default in the + // debugger, vs. USR1 or other named signals) + inline for ([_]usize{ posix.SIG.URG, posix.SIG.CHLD, 62, 94, 126 }) |test_signo| { if (test_signo >= posix.NSIG) continue; S.expected_sig = test_signo; S.handler_called_count = 0; - var sa: posix.Sigaction = .{ + const sa: posix.Sigaction = .{ .handler = .{ .sigaction = &S.handler }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = posix.SA.SIGINFO | posix.SA.RESETHAND, }; - posix.sigemptyset(&sa.mask); + var old_sa: posix.Sigaction = undefined; // Install the new signal handler. posix.sigaction(test_signo, &sa, &old_sa); // block the signal and see that its delayed until unblocked - var block_one: posix.sigset_t = undefined; - posix.sigemptyset(&block_one); + var block_one: posix.sigset_t = posix.sigemptyset(); posix.sigaddset(&block_one, test_signo); posix.sigprocmask(posix.SIG.BLOCK, &block_one, null); diff --git a/lib/std/start.zig b/lib/std/start.zig index a7421f80f7..6495db1c51 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -745,14 +745,13 @@ fn maybeIgnoreSigpipe() void { if (have_sigpipe_support and !std.options.keep_sigpipe) { const posix = std.posix; - var act: posix.Sigaction = .{ + const act: posix.Sigaction = .{ // Set handler to a noop function instead of `SIG.IGN` to prevent // leaking signal disposition to a child process. .handler = .{ .handler = noopSigHandler }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = 0, }; - posix.sigemptyset(&act.mask); posix.sigaction(posix.SIG.PIPE, &act, null); } } diff --git a/src/crash_report.zig b/src/crash_report.zig index 6e207ca74a..6f043c3bfb 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -175,12 +175,11 @@ pub fn attachSegfaultHandler() void { _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); return; } - var act: posix.Sigaction = .{ + const act: posix.Sigaction = .{ .handler = .{ .sigaction = handleSegfaultPosix }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND), }; - posix.sigemptyset(&act.mask); debug.updateSegfaultHandler(&act); } diff --git a/test/standalone/sigpipe/build.zig b/test/standalone/sigpipe/build.zig index da2c765182..de06e1df15 100644 --- a/test/standalone/sigpipe/build.zig +++ b/test/standalone/sigpipe/build.zig @@ -16,12 +16,11 @@ pub fn build(b: *std.build.Builder) !void { // This test runs "breakpipe" as a child process and that process // depends on inheriting a SIGPIPE disposition of "default". { - var act = posix.Sigaction{ + const act = posix.Sigaction{ .handler = .{ .handler = posix.SIG.DFL }, - .mask = undefined, + .mask = posix.sigemptyset(), .flags = 0, }; - posix.sigemptyset(&act.mask); try posix.sigaction(posix.SIG.PIPE, &act, null); } -- cgit v1.2.3