authorgravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2025-04-22 14:19:06-07:00
committergravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2025-04-30 20:32:04-07:00
log120c4789c31c066f15fe414a5b32cdc7e80a065c
treee45c5a1dd84791676bb8f516fc0c2c0200cfe0c0
parentf0aefa625b5b0d0b3612cfba9bd25c825a71818f

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.

11 files changed, 65 insertions(+), 63 deletions(-)

lib/std/Progress.zig+2-3
......@@ -410,12 +410,11 @@ pub fn start(options: Options) Node {
410410 }
411411
412412 if (have_sigwinch) {
413 var act: posix.Sigaction = .{
413 const act: posix.Sigaction = .{
414414 .handler = .{ .sigaction = handleSigWinch },
415 .mask = undefined,
415 .mask = posix.sigemptyset(),
416416 .flags = (posix.SA.SIGINFO | posix.SA.RESTART),
417417 };
418 posix.sigemptyset(&act.mask);
419418 posix.sigaction(posix.SIG.WINCH, &act, null);
420419 }
421420
lib/std/debug.zig+4-7
......@@ -1387,13 +1387,11 @@ pub fn attachSegfaultHandler() void {
13871387 windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
13881388 return;
13891389 }
1390 var act = posix.Sigaction{
1390 const act = posix.Sigaction{
13911391 .handler = .{ .sigaction = handleSegfaultPosix },
1392 .mask = undefined,
1392 .mask = posix.sigemptyset(),
13931393 .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
13941394 };
1395 posix.sigemptyset(&act.mask);
1396
13971395 updateSegfaultHandler(&act);
13981396}
13991397
......@@ -1405,12 +1403,11 @@ fn resetSegfaultHandler() void {
14051403 }
14061404 return;
14071405 }
1408 var act = posix.Sigaction{
1406 const act = posix.Sigaction{
14091407 .handler = .{ .handler = posix.SIG.DFL },
1410 .mask = undefined,
1408 .mask = posix.sigemptyset(),
14111409 .flags = 0,
14121410 };
1413 posix.sigemptyset(&act.mask);
14141411 updateSegfaultHandler(&act);
14151412}
14161413
lib/std/os/emscripten.zig+3-1
......@@ -560,7 +560,9 @@ pub const Sigaction = extern struct {
560560};
561561
562562pub const sigset_t = [1024 / 32]u32;
563pub const empty_sigset = [_]u32{0} ** @typeInfo(sigset_t).array.len;
563pub fn sigemptyset() sigset_t {
564 return [_]u32{0} ** @typeInfo(sigset_t).array.len;
565}
564566pub const siginfo_t = extern struct {
565567 signo: i32,
566568 errno: i32,
lib/std/os/linux.zig+8-4
......@@ -1800,11 +1800,15 @@ const SigsetElement = c_ulong;
18001800
18011801const sigset_len = @typeInfo(sigset_t).array.len;
18021802
1803/// Empty set to initialize sigset_t instances from. No need for `sigemptyset`.
1804pub const empty_sigset: sigset_t = [_]SigsetElement{0} ** sigset_len;
1803/// Zig's version of sigemptyset. Returns initialized sigset_t.
1804pub fn sigemptyset() sigset_t {
1805 return [_]SigsetElement{0} ** sigset_len;
1806}
18051807
1806/// Filled set to initialize sigset_t instances from. No need for `sigfillset`.
1807pub const filled_sigset: sigset_t = [_]SigsetElement{~@as(SigsetElement, 0)} ** sigset_len;
1808/// Zig's version of sigfillset. Returns initalized sigset_t.
1809pub fn sigfillset() sigset_t {
1810 return [_]SigsetElement{~@as(SigsetElement, 0)} ** sigset_len;
1811}
18081812
18091813fn sigset_bit_index(sig: usize) struct { word: usize, mask: SigsetElement } {
18101814 assert(sig > 0);
lib/std/os/linux/test.zig+5-7
......@@ -128,7 +128,7 @@ test "fadvise" {
128128test "sigset_t" {
129129 std.debug.assert(@sizeOf(linux.sigset_t) == (linux.NSIG / 8));
130130
131 var sigset = linux.empty_sigset;
131 var sigset = linux.sigemptyset();
132132
133133 // See that none are set, then set each one, see that they're all set, then
134134 // remove them all, and then see that none are set.
......@@ -140,8 +140,6 @@ test "sigset_t" {
140140 }
141141 for (1..linux.NSIG) |i| {
142142 try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
143 try expectEqual(linux.sigismember(&linux.filled_sigset, @truncate(i)), true);
144 try expectEqual(linux.sigismember(&linux.empty_sigset, @truncate(i)), false);
145143 }
146144 for (1..linux.NSIG) |i| {
147145 linux.sigdelset(&sigset, @truncate(i));
......@@ -183,16 +181,16 @@ test "sigset_t" {
183181 }
184182}
185183
186test "filled_sigset" {
184test "sigfillset" {
187185 // unlike the C library, all the signals are set in the kernel-level fillset
188 const sigset = linux.filled_sigset;
186 const sigset = linux.sigfillset();
189187 for (1..linux.NSIG) |i| {
190188 try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
191189 }
192190}
193191
194test "empty_sigset" {
195 const sigset = linux.empty_sigset;
192test "sigemptyset" {
193 const sigset = linux.sigemptyset();
196194 for (1..linux.NSIG) |i| {
197195 try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
198196 }
lib/std/os/plan9.zig+4-1
......@@ -182,7 +182,6 @@ pub const SIG = struct {
182182 pub const TTOU = 20;
183183};
184184pub const sigset_t = c_long;
185pub const empty_sigset = 0;
186185pub const siginfo_t = c_long;
187186// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we include it here to be compatible.
188187pub const Sigaction = extern struct {
......@@ -199,6 +198,10 @@ pub const Sigaction = extern struct {
199198pub const AT = struct {
200199 pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
201200};
201// Plan 9 doesn't do signals. This is just needed to get through start.zig.
202pub fn sigemptyset() sigset_t {
203 return 0;
204}
202205// TODO implement sigaction
203206// right now it is just a shim to allow using start.zig code
204207pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
lib/std/posix.zig+17-12
......@@ -677,7 +677,8 @@ pub fn abort() noreturn {
677677 raise(SIG.ABRT) catch {};
678678
679679 // Disable all signal handlers.
680 sigprocmask(SIG.BLOCK, &linux.filled_sigset, null);
680 const filledset = linux.sigfillset();
681 sigprocmask(SIG.BLOCK, &filledset, null);
681682
682683 // Only one thread may proceed to the rest of abort().
683684 if (!builtin.single_threaded) {
......@@ -690,14 +691,14 @@ pub fn abort() noreturn {
690691 // Install default handler so that the tkill below will terminate.
691692 const sigact = Sigaction{
692693 .handler = .{ .handler = SIG.DFL },
693 .mask = linux.empty_sigset,
694 .mask = sigemptyset(),
694695 .flags = 0,
695696 };
696697 sigaction(SIG.ABRT, &sigact, null);
697698
698699 _ = linux.tkill(linux.gettid(), SIG.ABRT);
699700
700 var sigabrtmask = linux.empty_sigset;
701 var sigabrtmask = sigemptyset();
701702 sigaddset(&sigabrtmask, SIG.ABRT);
702703 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
703704
......@@ -727,7 +728,7 @@ pub fn raise(sig: u8) RaiseError!void {
727728 // cannot trigger an extra, unexpected, inter-process signal. Signal paranoia inherited from Musl.
728729 const filled = linux.sigfillset();
729730 var orig: sigset_t = undefined;
730 sigprocmask(SIG.BLOCK, &linux.filled_sigset, &orig);
731 sigprocmask(SIG.BLOCK, &filled, &orig);
731732 const rc = linux.tkill(linux.gettid(), sig);
732733 sigprocmask(SIG.SETMASK, &orig, null);
733734
......@@ -5813,24 +5814,28 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
58135814 }
58145815}
58155816
5816pub fn sigfillset(set: *sigset_t) void {
5817/// Return a filled sigset_t.
5818pub fn sigfillset() sigset_t {
58175819 if (builtin.link_libc) {
5818 switch (errno(system.sigfillset(set))) {
5819 .SUCCESS => return,
5820 var set: sigset_t = undefined;
5821 switch (errno(system.sigfillset(&set))) {
5822 .SUCCESS => return set,
58205823 else => unreachable,
58215824 }
58225825 }
5823 set.* = system.filled_sigset;
5826 return system.sigfillset();
58245827}
58255828
5826pub fn sigemptyset(set: *sigset_t) void {
5829/// Return an empty sigset_t.
5830pub fn sigemptyset() sigset_t {
58275831 if (builtin.link_libc) {
5828 switch (errno(system.sigemptyset(set))) {
5829 .SUCCESS => return,
5832 var set: sigset_t = undefined;
5833 switch (errno(system.sigemptyset(&set))) {
5834 .SUCCESS => return set,
58305835 else => unreachable,
58315836 }
58325837 }
5833 set.* = mem.zeroes(sigset_t);
5838 return system.sigemptyset();
58345839}
58355840
58365841pub fn sigaddset(set: *sigset_t, sig: u8) void {
lib/std/posix/test.zig+16-19
......@@ -863,17 +863,15 @@ test "sigset empty/full" {
863863 if (native_os == .wasi or native_os == .windows)
864864 return error.SkipZigTest;
865865
866 var set: posix.sigset_t = undefined;
867
868 posix.sigemptyset(&set);
866 var set: posix.sigset_t = posix.sigemptyset();
869867 for (1..posix.NSIG) |i| {
870868 try expectEqual(false, posix.sigismember(&set, @truncate(i)));
871869 }
872870
873871 // The C library can reserve some (unnamed) signals, so can't check the full
874872 // NSIG set is defined, but just test a couple:
875 posix.sigfillset(&set);
876 try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.USR1)));
873 set = posix.sigfillset();
874 try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.CHLD)));
877875 try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT)));
878876}
879877
......@@ -887,8 +885,7 @@ test "sigset add/del" {
887885 if (native_os == .wasi or native_os == .windows)
888886 return error.SkipZigTest;
889887
890 var sigset: posix.sigset_t = undefined;
891 posix.sigemptyset(&sigset);
888 var sigset: posix.sigset_t = posix.sigemptyset();
892889
893890 // See that none are set, then set each one, see that they're all set, then
894891 // remove them all, and then see that none are set.
......@@ -924,7 +921,7 @@ test "sigaction" {
924921 return error.SkipZigTest;
925922 }
926923
927 const test_signo = posix.SIG.USR1;
924 const test_signo = posix.SIG.URG; // URG only because it is ignored by default in debuggers
928925
929926 const S = struct {
930927 var handler_called_count: u32 = 0;
......@@ -944,10 +941,10 @@ test "sigaction" {
944941
945942 var sa: posix.Sigaction = .{
946943 .handler = .{ .sigaction = &S.handler },
947 .mask = undefined,
944 .mask = posix.sigemptyset(),
948945 .flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
949946 };
950 posix.sigemptyset(&sa.mask);
947
951948 var old_sa: posix.Sigaction = undefined;
952949
953950 // Install the new signal handler.
......@@ -1009,29 +1006,29 @@ test "sigset_t bits" {
10091006
10101007 const self_pid = posix.system.getpid();
10111008
1012 // To check that sigset_t mapping matches kernel (think u32/u64
1013 // mismatches on big-endian), try sending a blocked signal to make
1014 // sure the mask matches the signal.
1015 inline for ([_]usize{ posix.SIG.INT, posix.SIG.USR1, 62, 94, 126 }) |test_signo| {
1009 // To check that sigset_t mapping matches kernel (think u32/u64 mismatches on
1010 // big-endian), try sending a blocked signal to make sure the mask matches the
1011 // signal. (Send URG and CHLD because they're ignored by default in the
1012 // debugger, vs. USR1 or other named signals)
1013 inline for ([_]usize{ posix.SIG.URG, posix.SIG.CHLD, 62, 94, 126 }) |test_signo| {
10161014 if (test_signo >= posix.NSIG) continue;
10171015
10181016 S.expected_sig = test_signo;
10191017 S.handler_called_count = 0;
10201018
1021 var sa: posix.Sigaction = .{
1019 const sa: posix.Sigaction = .{
10221020 .handler = .{ .sigaction = &S.handler },
1023 .mask = undefined,
1021 .mask = posix.sigemptyset(),
10241022 .flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
10251023 };
1026 posix.sigemptyset(&sa.mask);
1024
10271025 var old_sa: posix.Sigaction = undefined;
10281026
10291027 // Install the new signal handler.
10301028 posix.sigaction(test_signo, &sa, &old_sa);
10311029
10321030 // block the signal and see that its delayed until unblocked
1033 var block_one: posix.sigset_t = undefined;
1034 posix.sigemptyset(&block_one);
1031 var block_one: posix.sigset_t = posix.sigemptyset();
10351032 posix.sigaddset(&block_one, test_signo);
10361033 posix.sigprocmask(posix.SIG.BLOCK, &block_one, null);
10371034
lib/std/start.zig+2-3
......@@ -745,14 +745,13 @@ fn maybeIgnoreSigpipe() void {
745745
746746 if (have_sigpipe_support and !std.options.keep_sigpipe) {
747747 const posix = std.posix;
748 var act: posix.Sigaction = .{
748 const act: posix.Sigaction = .{
749749 // Set handler to a noop function instead of `SIG.IGN` to prevent
750750 // leaking signal disposition to a child process.
751751 .handler = .{ .handler = noopSigHandler },
752 .mask = undefined,
752 .mask = posix.sigemptyset(),
753753 .flags = 0,
754754 };
755 posix.sigemptyset(&act.mask);
756755 posix.sigaction(posix.SIG.PIPE, &act, null);
757756 }
758757}
src/crash_report.zig+2-3
......@@ -175,12 +175,11 @@ pub fn attachSegfaultHandler() void {
175175 _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
176176 return;
177177 }
178 var act: posix.Sigaction = .{
178 const act: posix.Sigaction = .{
179179 .handler = .{ .sigaction = handleSegfaultPosix },
180 .mask = undefined,
180 .mask = posix.sigemptyset(),
181181 .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
182182 };
183 posix.sigemptyset(&act.mask);
184183 debug.updateSegfaultHandler(&act);
185184}
186185
test/standalone/sigpipe/build.zig+2-3
......@@ -16,12 +16,11 @@ pub fn build(b: *std.build.Builder) !void {
1616 // This test runs "breakpipe" as a child process and that process
1717 // depends on inheriting a SIGPIPE disposition of "default".
1818 {
19 var act = posix.Sigaction{
19 const act = posix.Sigaction{
2020 .handler = .{ .handler = posix.SIG.DFL },
21 .mask = undefined,
21 .mask = posix.sigemptyset(),
2222 .flags = 0,
2323 };
24 posix.sigemptyset(&act.mask);
2524 try posix.sigaction(posix.SIG.PIPE, &act, null);
2625 }
2726