authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-01 21:29:23+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-05-01 21:29:23+02:00
logad9cb401124e4b2d59e49bed2736aad7813e4f1d
tree7bafd4a5dac886e67bb8f63ecfa22ae3bb2084c1
parent971d19a3b2ca97b9acd00d74556a57a335898ed8
parenta55ecd7532e7ae015afe5cb5bc16b89376a4bf56
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #23601 from rootbeer/sig-split

Split glibc and linux sigset_t ABIs and the accessor functions

22 files changed, 393 insertions(+), 155 deletions(-)

lib/std/Progress.zig+2-2
...@@ -410,9 +410,9 @@ pub fn start(options: Options) Node {...@@ -410,9 +410,9 @@ pub fn start(options: Options) Node {
410 }410 }
411411
412 if (have_sigwinch) {412 if (have_sigwinch) {
413 var act: posix.Sigaction = .{413 const act: posix.Sigaction = .{
414 .handler = .{ .sigaction = handleSigWinch },414 .handler = .{ .sigaction = handleSigWinch },
415 .mask = posix.empty_sigset,415 .mask = posix.sigemptyset(),
416 .flags = (posix.SA.SIGINFO | posix.SA.RESTART),416 .flags = (posix.SA.SIGINFO | posix.SA.RESTART),
417 };417 };
418 posix.sigaction(posix.SIG.WINCH, &act, null);418 posix.sigaction(posix.SIG.WINCH, &act, null);
lib/std/c.zig+34-19
...@@ -3115,6 +3115,21 @@ pub const SYS = switch (native_os) {...@@ -3115,6 +3115,21 @@ pub const SYS = switch (native_os) {
3115 .linux => linux.SYS,3115 .linux => linux.SYS,
3116 else => void,3116 else => void,
3117};3117};
3118
3119/// A common format for the Sigaction struct across a variety of Linux flavors.
3120const common_linux_Sigaction = extern struct {
3121 pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;
3122 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;
3123
3124 handler: extern union {
3125 handler: ?handler_fn,
3126 sigaction: ?sigaction_fn,
3127 },
3128 mask: sigset_t,
3129 flags: c_uint,
3130 restorer: ?*const fn () callconv(.c) void = null, // C library will fill this in
3131};
3132
3118/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.3133/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
3119pub const Sigaction = switch (native_os) {3134pub const Sigaction = switch (native_os) {
3120 .linux => switch (native_arch) {3135 .linux => switch (native_arch) {
...@@ -3123,7 +3138,7 @@ pub const Sigaction = switch (native_os) {...@@ -3123,7 +3138,7 @@ pub const Sigaction = switch (native_os) {
3123 .mips64,3138 .mips64,
3124 .mips64el,3139 .mips64el,
3125 => if (builtin.target.abi.isMusl())3140 => if (builtin.target.abi.isMusl())
3126 linux.Sigaction3141 common_linux_Sigaction
3127 else if (builtin.target.ptrBitWidth() == 64) extern struct {3142 else if (builtin.target.ptrBitWidth() == 64) extern struct {
3128 pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;3143 pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;
3129 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;3144 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;
...@@ -3160,8 +3175,8 @@ pub const Sigaction = switch (native_os) {...@@ -3160,8 +3175,8 @@ pub const Sigaction = switch (native_os) {
3160 flags: c_uint,3175 flags: c_uint,
3161 restorer: ?*const fn () callconv(.c) void = null,3176 restorer: ?*const fn () callconv(.c) void = null,
3162 mask: sigset_t,3177 mask: sigset_t,
3163 } else linux.Sigaction,3178 } else common_linux_Sigaction,
3164 else => linux.Sigaction,3179 else => common_linux_Sigaction,
3165 },3180 },
3166 .emscripten => emscripten.Sigaction,3181 .emscripten => emscripten.Sigaction,
3167 .netbsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {3182 .netbsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
...@@ -4518,27 +4533,18 @@ pub const siginfo_t = switch (native_os) {...@@ -4518,27 +4533,18 @@ pub const siginfo_t = switch (native_os) {
4518 else => void,4533 else => void,
4519};4534};
4520pub const sigset_t = switch (native_os) {4535pub const sigset_t = switch (native_os) {
4521 .linux => linux.sigset_t,4536 .linux => [1024 / @bitSizeOf(c_ulong)]c_ulong, // glibc and musl present a 1024-bit sigset_t, while kernel's is 128-bit or less.
4522 .emscripten => emscripten.sigset_t,4537 .emscripten => emscripten.sigset_t,
4523 // https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L194538 // https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L19
4524 .openbsd, .macos, .ios, .tvos, .watchos, .visionos, .serenity => u32,4539 .openbsd, .serenity => u32,
4540 .macos, .ios, .tvos, .watchos, .visionos => darwin.sigset_t,
4525 .dragonfly, .netbsd, .solaris, .illumos, .freebsd => extern struct {4541 .dragonfly, .netbsd, .solaris, .illumos, .freebsd => extern struct {
4526 __bits: [SIG.WORDS]u32,4542 __bits: [SIG.WORDS]u32,
4527 },4543 },
4528 .haiku => u64,4544 .haiku => u64,
4529 else => u0,4545 else => u0,
4530};4546};
4531pub const empty_sigset: sigset_t = switch (native_os) {4547
4532 .linux => linux.empty_sigset,
4533 .emscripten => emscripten.empty_sigset,
4534 .dragonfly, .netbsd, .solaris, .illumos, .freebsd => .{ .__bits = [_]u32{0} ** SIG.WORDS },
4535 else => 0,
4536};
4537pub const filled_sigset = switch (native_os) {
4538 .linux => linux.filled_sigset,
4539 .haiku => ~@as(sigset_t, 0),
4540 else => 0,
4541};
4542pub const sigval = switch (native_os) {4548pub const sigval = switch (native_os) {
4543 .linux => linux.sigval,4549 .linux => linux.sigval,
4544 // https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L22-L254550 // https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L22-L25
...@@ -6665,7 +6671,7 @@ pub const timezone = switch (native_os) {...@@ -6665,7 +6671,7 @@ pub const timezone = switch (native_os) {
6665};6671};
66666672
6667pub const ucontext_t = switch (native_os) {6673pub const ucontext_t = switch (native_os) {
6668 .linux => linux.ucontext_t,6674 .linux => linux.ucontext_t, // std.os.linux.ucontext_t is currently glibc-compatible, but it should probably not be.
6669 .emscripten => emscripten.ucontext_t,6675 .emscripten => emscripten.ucontext_t,
6670 .macos, .ios, .tvos, .watchos, .visionos => extern struct {6676 .macos, .ios, .tvos, .watchos, .visionos => extern struct {
6671 onstack: c_int,6677 onstack: c_int,
...@@ -9596,6 +9602,7 @@ pub const NSIG = switch (native_os) {...@@ -9596,6 +9602,7 @@ pub const NSIG = switch (native_os) {
9596 .windows => 23,9602 .windows => 23,
9597 .haiku => 65,9603 .haiku => 65,
9598 .netbsd, .freebsd => 32,9604 .netbsd, .freebsd => 32,
9605 .macos => darwin.NSIG,
9599 .solaris, .illumos => 75,9606 .solaris, .illumos => 75,
9600 // https://github.com/SerenityOS/serenity/blob/046c23f567a17758d762a33bdf04bacbfd088f9f/Kernel/API/POSIX/signal_numbers.h#L429607 // https://github.com/SerenityOS/serenity/blob/046c23f567a17758d762a33bdf04bacbfd088f9f/Kernel/API/POSIX/signal_numbers.h#L42
9601 .openbsd, .serenity => 33,9608 .openbsd, .serenity => 33,
...@@ -10345,6 +10352,11 @@ pub const sigfillset = switch (native_os) {...@@ -10345,6 +10352,11 @@ pub const sigfillset = switch (native_os) {
10345 else => private.sigfillset,10352 else => private.sigfillset,
10346};10353};
1034710354
10355pub const sigaddset = private.sigaddset;
10356pub const sigemptyset = private.sigemptyset;
10357pub const sigdelset = private.sigdelset;
10358pub const sigismember = private.sigismember;
10359
10348pub const sigprocmask = switch (native_os) {10360pub const sigprocmask = switch (native_os) {
10349 .netbsd => private.__sigprocmask14,10361 .netbsd => private.__sigprocmask14,
10350 else => private.sigprocmask,10362 else => private.sigprocmask,
...@@ -11025,7 +11037,6 @@ pub const pthread_attr_set_qos_class_np = darwin.pthread_attr_set_qos_class_np;...@@ -11025,7 +11037,6 @@ pub const pthread_attr_set_qos_class_np = darwin.pthread_attr_set_qos_class_np;
11025pub const pthread_get_qos_class_np = darwin.pthread_get_qos_class_np;11037pub const pthread_get_qos_class_np = darwin.pthread_get_qos_class_np;
11026pub const pthread_set_qos_class_self_np = darwin.pthread_set_qos_class_self_np;11038pub const pthread_set_qos_class_self_np = darwin.pthread_set_qos_class_self_np;
11027pub const ptrace = darwin.ptrace;11039pub const ptrace = darwin.ptrace;
11028pub const sigaddset = darwin.sigaddset;
11029pub const task_for_pid = darwin.task_for_pid;11040pub const task_for_pid = darwin.task_for_pid;
11030pub const task_get_exception_ports = darwin.task_get_exception_ports;11041pub const task_get_exception_ports = darwin.task_get_exception_ports;
11031pub const task_info = darwin.task_info;11042pub const task_info = darwin.task_info;
...@@ -11148,7 +11159,11 @@ const private = struct {...@@ -11148,7 +11159,11 @@ const private = struct {
11148 extern "c" fn sched_yield() c_int;11159 extern "c" fn sched_yield() c_int;
11149 extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize;11160 extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize;
11150 extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;11161 extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
11151 extern "c" fn sigfillset(set: ?*sigset_t) void;11162 extern "c" fn sigdelset(set: ?*sigset_t, signo: c_int) c_int;
11163 extern "c" fn sigaddset(set: ?*sigset_t, signo: c_int) c_int;
11164 extern "c" fn sigfillset(set: ?*sigset_t) c_int;
11165 extern "c" fn sigemptyset(set: ?*sigset_t) c_int;
11166 extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int;
11152 extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;11167 extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
11153 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;11168 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
11154 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;11169 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
lib/std/c/darwin.zig+5-4
...@@ -10,7 +10,6 @@ const mode_t = std.c.mode_t;...@@ -10,7 +10,6 @@ const mode_t = std.c.mode_t;
10const off_t = std.c.off_t;10const off_t = std.c.off_t;
11const pid_t = std.c.pid_t;11const pid_t = std.c.pid_t;
12const pthread_attr_t = std.c.pthread_attr_t;12const pthread_attr_t = std.c.pthread_attr_t;
13const sigset_t = std.c.sigset_t;
14const timespec = std.c.timespec;13const timespec = std.c.timespec;
15const sf_hdtr = std.c.sf_hdtr;14const sf_hdtr = std.c.sf_hdtr;
1615
...@@ -840,9 +839,11 @@ pub extern "c" fn sendfile(...@@ -840,9 +839,11 @@ pub extern "c" fn sendfile(
840 flags: u32,839 flags: u32,
841) c_int;840) c_int;
842841
843pub fn sigaddset(set: *sigset_t, signo: u5) void {842// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/_types.h#L74
844 set.* |= @as(u32, 1) << (signo - 1);843pub const sigset_t = u32;
845}844
845// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/signal.h#L76
846pub const NSIG = 32;
846847
847pub const qos_class_t = enum(c_uint) {848pub const qos_class_t = enum(c_uint) {
848 /// highest priority QOS class for critical tasks849 /// highest priority QOS class for critical tasks
lib/std/debug.zig+4-5
...@@ -1387,12 +1387,11 @@ pub fn attachSegfaultHandler() void {...@@ -1387,12 +1387,11 @@ pub fn attachSegfaultHandler() void {
1387 windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);1387 windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
1388 return;1388 return;
1389 }1389 }
1390 var act = posix.Sigaction{1390 const act = posix.Sigaction{
1391 .handler = .{ .sigaction = handleSegfaultPosix },1391 .handler = .{ .sigaction = handleSegfaultPosix },
1392 .mask = posix.empty_sigset,1392 .mask = posix.sigemptyset(),
1393 .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),1393 .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
1394 };1394 };
1395
1396 updateSegfaultHandler(&act);1395 updateSegfaultHandler(&act);
1397}1396}
13981397
...@@ -1404,9 +1403,9 @@ fn resetSegfaultHandler() void {...@@ -1404,9 +1403,9 @@ fn resetSegfaultHandler() void {
1404 }1403 }
1405 return;1404 return;
1406 }1405 }
1407 var act = posix.Sigaction{1406 const act = posix.Sigaction{
1408 .handler = .{ .handler = posix.SIG.DFL },1407 .handler = .{ .handler = posix.SIG.DFL },
1409 .mask = posix.empty_sigset,1408 .mask = posix.sigemptyset(),
1410 .flags = 0,1409 .flags = 0,
1411 };1410 };
1412 updateSegfaultHandler(&act);1411 updateSegfaultHandler(&act);
lib/std/os/emscripten.zig+3-1
...@@ -560,7 +560,9 @@ pub const Sigaction = extern struct {...@@ -560,7 +560,9 @@ pub const Sigaction = extern struct {
560};560};
561561
562pub const sigset_t = [1024 / 32]u32;562pub 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}
564pub const siginfo_t = extern struct {566pub const siginfo_t = extern struct {
565 signo: i32,567 signo: i32,
566 errno: i32,568 errno: i32,
lib/std/os/linux.zig+62-53
...@@ -1745,8 +1745,9 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*...@@ -1745,8 +1745,9 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*
1745 return syscall4(.rt_sigprocmask, flags, @intFromPtr(set), @intFromPtr(oldset), NSIG / 8);1745 return syscall4(.rt_sigprocmask, flags, @intFromPtr(set), @intFromPtr(oldset), NSIG / 8);
1746}1746}
17471747
1748pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {1748pub fn sigaction(sig: u8, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
1749 assert(sig >= 1);1749 assert(sig > 0);
1750 assert(sig < NSIG);
1750 assert(sig != SIG.KILL);1751 assert(sig != SIG.KILL);
1751 assert(sig != SIG.STOP);1752 assert(sig != SIG.STOP);
17521753
...@@ -1755,14 +1756,15 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -1755,14 +1756,15 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
1755 const mask_size = @sizeOf(@TypeOf(ksa.mask));1756 const mask_size = @sizeOf(@TypeOf(ksa.mask));
17561757
1757 if (act) |new| {1758 if (act) |new| {
1759 // Zig needs to install our arch restorer function with any signal handler, so
1760 // must copy the Sigaction struct
1758 const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) &restore_rt else &restore;1761 const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) &restore_rt else &restore;
1759 ksa = k_sigaction{1762 ksa = k_sigaction{
1760 .handler = new.handler.handler,1763 .handler = new.handler.handler,
1761 .flags = new.flags | SA.RESTORER,1764 .flags = new.flags | SA.RESTORER,
1762 .mask = undefined,1765 .mask = new.mask,
1763 .restorer = @ptrCast(restorer_fn),1766 .restorer = @ptrCast(restorer_fn),
1764 };1767 };
1765 @memcpy(@as([*]u8, @ptrCast(&ksa.mask))[0..mask_size], @as([*]const u8, @ptrCast(&new.mask)));
1766 }1768 }
17671769
1768 const ksa_arg = if (act != null) @intFromPtr(&ksa) else 0;1770 const ksa_arg = if (act != null) @intFromPtr(&ksa) else 0;
...@@ -1777,8 +1779,8 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -1777,8 +1779,8 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
17771779
1778 if (oact) |old| {1780 if (oact) |old| {
1779 old.handler.handler = oldksa.handler;1781 old.handler.handler = oldksa.handler;
1780 old.flags = @as(c_uint, @truncate(oldksa.flags));1782 old.flags = oldksa.flags;
1781 @memcpy(@as([*]u8, @ptrCast(&old.mask))[0..mask_size], @as([*]const u8, @ptrCast(&oldksa.mask)));1783 old.mask = oldksa.mask;
1782 }1784 }
17831785
1784 return 0;1786 return 0;
...@@ -1786,25 +1788,35 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -1786,25 +1788,35 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
17861788
1787const usize_bits = @typeInfo(usize).int.bits;1789const usize_bits = @typeInfo(usize).int.bits;
17881790
1789pub const sigset_t = [1024 / 32]u32;1791/// Defined as one greater than the largest defined signal number.
1792pub const NSIG = if (is_mips) 128 else 65;
17901793
1791const sigset_len = @typeInfo(sigset_t).array.len;1794/// Linux kernel's sigset_t. This is logically 64-bit on most
1795/// architectures, but 128-bit on MIPS. Contrast with the 1024-bit
1796/// sigset_t exported by the glibc and musl library ABIs.
1797pub const sigset_t = [(NSIG - 1 + 7) / @bitSizeOf(SigsetElement)]SigsetElement;
17921798
1793/// Empty set to initialize sigset_t instances from.1799const SigsetElement = c_ulong;
1794pub const empty_sigset: sigset_t = [_]u32{0} ** sigset_len;
17951800
1796pub const filled_sigset: sigset_t = [_]u32{0x7fff_ffff} ++ [_]u32{0} ** (sigset_len - 1);1801const sigset_len = @typeInfo(sigset_t).array.len;
17971802
1798pub const all_mask: sigset_t = [_]u32{0xffff_ffff} ** sigset_len;1803/// Zig's version of sigemptyset. Returns initialized sigset_t.
1804pub fn sigemptyset() sigset_t {
1805 return [_]SigsetElement{0} ** sigset_len;
1806}
17991807
1800fn sigset_bit_index(sig: usize) struct { word: usize, mask: u32 } {1808/// Zig's version of sigfillset. Returns initalized sigset_t.
1809pub fn sigfillset() sigset_t {
1810 return [_]SigsetElement{~@as(SigsetElement, 0)} ** sigset_len;
1811}
1812
1813fn sigset_bit_index(sig: usize) struct { word: usize, mask: SigsetElement } {
1801 assert(sig > 0);1814 assert(sig > 0);
1802 assert(sig < NSIG);1815 assert(sig < NSIG);
1803 const bit = sig - 1;1816 const bit = sig - 1;
1804 const shift = @as(u5, @truncate(bit % 32));
1805 return .{1817 return .{
1806 .word = bit / 32,1818 .word = bit / @bitSizeOf(SigsetElement),
1807 .mask = @as(u32, 1) << shift,1819 .mask = @as(SigsetElement, 1) << @truncate(bit % @bitSizeOf(SigsetElement)),
1808 };1820 };
1809}1821}
18101822
...@@ -3487,6 +3499,7 @@ pub const SIG = if (is_mips) struct {...@@ -3487,6 +3499,7 @@ pub const SIG = if (is_mips) struct {
3487 pub const UNBLOCK = 2;3499 pub const UNBLOCK = 2;
3488 pub const SETMASK = 3;3500 pub const SETMASK = 3;
34893501
3502 // https://github.com/torvalds/linux/blob/ca91b9500108d4cf083a635c2e11c884d5dd20ea/arch/mips/include/uapi/asm/signal.h#L25
3490 pub const HUP = 1;3503 pub const HUP = 1;
3491 pub const INT = 2;3504 pub const INT = 2;
3492 pub const QUIT = 3;3505 pub const QUIT = 3;
...@@ -3494,33 +3507,32 @@ pub const SIG = if (is_mips) struct {...@@ -3494,33 +3507,32 @@ pub const SIG = if (is_mips) struct {
3494 pub const TRAP = 5;3507 pub const TRAP = 5;
3495 pub const ABRT = 6;3508 pub const ABRT = 6;
3496 pub const IOT = ABRT;3509 pub const IOT = ABRT;
3497 pub const BUS = 7;3510 pub const EMT = 7;
3498 pub const FPE = 8;3511 pub const FPE = 8;
3499 pub const KILL = 9;3512 pub const KILL = 9;
3500 pub const USR1 = 10;3513 pub const BUS = 10;
3501 pub const SEGV = 11;3514 pub const SEGV = 11;
3502 pub const USR2 = 12;3515 pub const SYS = 12;
3503 pub const PIPE = 13;3516 pub const PIPE = 13;
3504 pub const ALRM = 14;3517 pub const ALRM = 14;
3505 pub const TERM = 15;3518 pub const TERM = 15;
3506 pub const STKFLT = 16;3519 pub const USR1 = 16;
3507 pub const CHLD = 17;3520 pub const USR2 = 17;
3508 pub const CONT = 18;3521 pub const CHLD = 18;
3509 pub const STOP = 19;3522 pub const PWR = 19;
3510 pub const TSTP = 20;3523 pub const WINCH = 20;
3511 pub const TTIN = 21;3524 pub const URG = 21;
3512 pub const TTOU = 22;3525 pub const IO = 22;
3513 pub const URG = 23;3526 pub const POLL = IO;
3514 pub const XCPU = 24;3527 pub const STOP = 23;
3515 pub const XFSZ = 25;3528 pub const TSTP = 24;
3516 pub const VTALRM = 26;3529 pub const CONT = 25;
3517 pub const PROF = 27;3530 pub const TTIN = 26;
3518 pub const WINCH = 28;3531 pub const TTOU = 27;
3519 pub const IO = 29;3532 pub const VTALRM = 28;
3520 pub const POLL = 29;3533 pub const PROF = 29;
3521 pub const PWR = 30;3534 pub const XCPU = 30;
3522 pub const SYS = 31;3535 pub const XFZ = 31;
3523 pub const UNUSED = SIG.SYS;
35243536
3525 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));3537 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
3526 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);3538 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
...@@ -5479,38 +5491,33 @@ pub const TFD = switch (native_arch) {...@@ -5479,38 +5491,33 @@ pub const TFD = switch (native_arch) {
5479 },5491 },
5480};5492};
54815493
5482/// NSIG is the total number of signals defined.
5483/// As signal numbers are sequential, NSIG is one greater than the largest defined signal number.
5484pub const NSIG = if (is_mips) 128 else 65;
5485
5486const k_sigaction_funcs = struct {5494const k_sigaction_funcs = struct {
5487 const handler = ?*align(1) const fn (i32) callconv(.c) void;5495 const handler = ?*align(1) const fn (i32) callconv(.c) void;
5488 const restorer = *const fn () callconv(.c) void;5496 const restorer = *const fn () callconv(.c) void;
5489};5497};
54905498
5499/// Kernel sigaction struct, as expected by the `rt_sigaction` syscall. Includes restorer.
5491pub const k_sigaction = switch (native_arch) {5500pub const k_sigaction = switch (native_arch) {
5492 .mips, .mipsel => extern struct {5501 .mips, .mipsel, .mips64, .mips64el => extern struct {
5493 flags: c_uint,
5494 handler: k_sigaction_funcs.handler,
5495 mask: [4]c_ulong,
5496 restorer: k_sigaction_funcs.restorer,
5497 },
5498 .mips64, .mips64el => extern struct {
5499 flags: c_uint,5502 flags: c_uint,
5500 handler: k_sigaction_funcs.handler,5503 handler: k_sigaction_funcs.handler,
5501 mask: [2]c_ulong,5504 mask: sigset_t,
5502 restorer: k_sigaction_funcs.restorer,5505 restorer: k_sigaction_funcs.restorer,
5503 },5506 },
5504 else => extern struct {5507 else => extern struct {
5505 handler: k_sigaction_funcs.handler,5508 handler: k_sigaction_funcs.handler,
5506 flags: c_ulong,5509 flags: c_ulong,
5507 restorer: k_sigaction_funcs.restorer,5510 restorer: k_sigaction_funcs.restorer,
5508 mask: [2]c_uint,5511 mask: sigset_t,
5509 },5512 },
5510};5513};
55115514
5515/// Kernel Sigaction wrapper for the actual ABI `k_sigaction`. The Zig
5516/// linux.zig wrapper library still does some pre-processing on
5517/// sigaction() calls (to add the `restorer` field).
5518///
5512/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.5519/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
5513pub const Sigaction = extern struct {5520pub const Sigaction = struct {
5514 pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;5521 pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;
5515 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;5522 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;
55165523
...@@ -5519,8 +5526,10 @@ pub const Sigaction = extern struct {...@@ -5519,8 +5526,10 @@ pub const Sigaction = extern struct {
5519 sigaction: ?sigaction_fn,5526 sigaction: ?sigaction_fn,
5520 },5527 },
5521 mask: sigset_t,5528 mask: sigset_t,
5522 flags: c_uint,5529 flags: switch (native_arch) {
5523 restorer: ?*const fn () callconv(.c) void = null,5530 .mips, .mipsel, .mips64, .mips64el => c_uint,
5531 else => c_ulong,
5532 },
5524};5533};
55255534
5526pub const SFD = struct {5535pub const SFD = struct {
lib/std/os/linux/aarch64.zig+1-1
...@@ -289,7 +289,7 @@ pub const ucontext_t = extern struct {...@@ -289,7 +289,7 @@ pub const ucontext_t = extern struct {
289 flags: usize,289 flags: usize,
290 link: ?*ucontext_t,290 link: ?*ucontext_t,
291 stack: stack_t,291 stack: stack_t,
292 sigmask: sigset_t,292 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
293 mcontext: mcontext_t,293 mcontext: mcontext_t,
294};294};
295295
lib/std/os/linux/arm.zig+1-1
...@@ -337,7 +337,7 @@ pub const ucontext_t = extern struct {...@@ -337,7 +337,7 @@ pub const ucontext_t = extern struct {
337 link: ?*ucontext_t,337 link: ?*ucontext_t,
338 stack: stack_t,338 stack: stack_t,
339 mcontext: mcontext_t,339 mcontext: mcontext_t,
340 sigmask: sigset_t,340 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
341 regspace: [64]u64,341 regspace: [64]u64,
342};342};
343343
lib/std/os/linux/loongarch64.zig+1-2
...@@ -264,8 +264,7 @@ pub const ucontext_t = extern struct {...@@ -264,8 +264,7 @@ pub const ucontext_t = extern struct {
264 flags: c_ulong,264 flags: c_ulong,
265 link: ?*ucontext_t,265 link: ?*ucontext_t,
266 stack: stack_t,266 stack: stack_t,
267 sigmask: sigset_t,267 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
268 _pad: [1024 / 8 - @sizeOf(sigset_t)]u8,
269 mcontext: mcontext_t,268 mcontext: mcontext_t,
270};269};
271270
lib/std/os/linux/powerpc.zig+1-1
...@@ -341,7 +341,7 @@ pub const ucontext_t = extern struct {...@@ -341,7 +341,7 @@ pub const ucontext_t = extern struct {
341 stack: stack_t,341 stack: stack_t,
342 pad: [7]i32,342 pad: [7]i32,
343 regs: *mcontext_t,343 regs: *mcontext_t,
344 sigmask: sigset_t,344 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
345 pad2: [3]i32,345 pad2: [3]i32,
346 mcontext: mcontext_t,346 mcontext: mcontext_t,
347};347};
lib/std/os/linux/powerpc64.zig+1-1
...@@ -337,7 +337,7 @@ pub const ucontext_t = extern struct {...@@ -337,7 +337,7 @@ pub const ucontext_t = extern struct {
337 flags: u32,337 flags: u32,
338 link: ?*ucontext_t,338 link: ?*ucontext_t,
339 stack: stack_t,339 stack: stack_t,
340 sigmask: sigset_t,340 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
341 mcontext: mcontext_t,341 mcontext: mcontext_t,
342};342};
343343
lib/std/os/linux/s390x.zig+1-1
...@@ -273,7 +273,7 @@ pub const ucontext_t = extern struct {...@@ -273,7 +273,7 @@ pub const ucontext_t = extern struct {
273 link: ?*ucontext_t,273 link: ?*ucontext_t,
274 stack: stack_t,274 stack: stack_t,
275 mcontext: mcontext_t,275 mcontext: mcontext_t,
276 sigmask: sigset_t,276 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
277};277};
278278
279pub const mcontext_t = extern struct {279pub const mcontext_t = extern struct {
lib/std/os/linux/sparc64.zig+1-1
...@@ -454,7 +454,7 @@ pub const ucontext_t = extern struct {...@@ -454,7 +454,7 @@ pub const ucontext_t = extern struct {
454 sigmask: u64,454 sigmask: u64,
455 mcontext: mcontext_t,455 mcontext: mcontext_t,
456 stack: stack_t,456 stack: stack_t,
457 sigset: sigset_t,457 sigset: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
458};458};
459459
460/// TODO460/// TODO
lib/std/os/linux/test.zig+40-9
...@@ -126,7 +126,9 @@ test "fadvise" {...@@ -126,7 +126,9 @@ test "fadvise" {
126}126}
127127
128test "sigset_t" {128test "sigset_t" {
129 var sigset = linux.empty_sigset;129 std.debug.assert(@sizeOf(linux.sigset_t) == (linux.NSIG / 8));
130
131 var sigset = linux.sigemptyset();
130132
131 // See that none are set, then set each one, see that they're all set, then133 // See that none are set, then set each one, see that they're all set, then
132 // remove them all, and then see that none are set.134 // remove them all, and then see that none are set.
...@@ -138,7 +140,6 @@ test "sigset_t" {...@@ -138,7 +140,6 @@ test "sigset_t" {
138 }140 }
139 for (1..linux.NSIG) |i| {141 for (1..linux.NSIG) |i| {
140 try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);142 try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
141 try expectEqual(linux.sigismember(&linux.empty_sigset, @truncate(i)), false);
142 }143 }
143 for (1..linux.NSIG) |i| {144 for (1..linux.NSIG) |i| {
144 linux.sigdelset(&sigset, @truncate(i));145 linux.sigdelset(&sigset, @truncate(i));
...@@ -147,22 +148,52 @@ test "sigset_t" {...@@ -147,22 +148,52 @@ test "sigset_t" {
147 try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);148 try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
148 }149 }
149150
151 // Kernel sigset_t is either 2+ 32-bit values or 1+ 64-bit value(s).
152 const sigset_len = @typeInfo(linux.sigset_t).array.len;
153 const sigset_elemis64 = 64 == @bitSizeOf(@typeInfo(linux.sigset_t).array.child);
154
150 linux.sigaddset(&sigset, 1);155 linux.sigaddset(&sigset, 1);
151 try expectEqual(sigset[0], 1);156 try expectEqual(sigset[0], 1);
152 try expectEqual(sigset[1], 0);157 if (sigset_len > 1) {
158 try expectEqual(sigset[1], 0);
159 }
153160
154 linux.sigaddset(&sigset, 31);161 linux.sigaddset(&sigset, 31);
155 try expectEqual(sigset[0], 0x4000_0001);162 try expectEqual(sigset[0], 0x4000_0001);
156 try expectEqual(sigset[1], 0);163 if (sigset_len > 1) {
164 try expectEqual(sigset[1], 0);
165 }
157166
158 linux.sigaddset(&sigset, 36);167 linux.sigaddset(&sigset, 36);
159 try expectEqual(sigset[0], 0x4000_0001);168 if (sigset_elemis64) {
160 try expectEqual(sigset[1], 0x8);169 try expectEqual(sigset[0], 0x8_4000_0001);
170 } else {
171 try expectEqual(sigset[0], 0x4000_0001);
172 try expectEqual(sigset[1], 0x8);
173 }
161174
162 linux.sigaddset(&sigset, 64);175 linux.sigaddset(&sigset, 64);
163 try expectEqual(sigset[0], 0x4000_0001);176 if (sigset_elemis64) {
164 try expectEqual(sigset[1], 0x8000_0008);177 try expectEqual(sigset[0], 0x8000_0008_4000_0001);
165 try expectEqual(sigset[2], 0);178 } else {
179 try expectEqual(sigset[0], 0x4000_0001);
180 try expectEqual(sigset[1], 0x8000_0008);
181 }
182}
183
184test "sigfillset" {
185 // unlike the C library, all the signals are set in the kernel-level fillset
186 const sigset = linux.sigfillset();
187 for (1..linux.NSIG) |i| {
188 try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
189 }
190}
191
192test "sigemptyset" {
193 const sigset = linux.sigemptyset();
194 for (1..linux.NSIG) |i| {
195 try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
196 }
166}197}
167198
168test "sysinfo" {199test "sysinfo" {
lib/std/os/linux/x86.zig+1-1
...@@ -350,7 +350,7 @@ pub const ucontext_t = extern struct {...@@ -350,7 +350,7 @@ pub const ucontext_t = extern struct {
350 link: ?*ucontext_t,350 link: ?*ucontext_t,
351 stack: stack_t,351 stack: stack_t,
352 mcontext: mcontext_t,352 mcontext: mcontext_t,
353 sigmask: sigset_t,353 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
354 regspace: [64]u64,354 regspace: [64]u64,
355};355};
356356
lib/std/os/linux/x86_64.zig+11-3
...@@ -369,13 +369,21 @@ pub const mcontext_t = extern struct {...@@ -369,13 +369,21 @@ pub const mcontext_t = extern struct {
369 reserved1: [8]usize = undefined,369 reserved1: [8]usize = undefined,
370};370};
371371
372/// ucontext_t is part of the state pushed on the stack by the kernel for
373/// a signal handler. And also a subset of the state returned from the
374/// makecontext/getcontext/swapcontext POSIX APIs.
375///
376/// Currently this structure matches the glibc/musl layout. It contains a
377/// 1024-bit signal mask, and `fpregs_mem`. This structure should be
378/// split into one for the kernel ABI and c.zig should define a glibc/musl
379/// compatible structure.
372pub const ucontext_t = extern struct {380pub const ucontext_t = extern struct {
373 flags: usize,381 flags: usize,
374 link: ?*ucontext_t,382 link: ?*ucontext_t,
375 stack: stack_t,383 stack: stack_t,
376 mcontext: mcontext_t,384 mcontext: mcontext_t,
377 sigmask: sigset_t,385 sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a glibc-compatible (1024-bit) sigmask.
378 fpregs_mem: [64]usize,386 fpregs_mem: [64]usize, // Not part of kernel ABI, only part of glibc ucontext_t
379};387};
380388
381fn gpRegisterOffset(comptime reg_index: comptime_int) usize {389fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
...@@ -455,7 +463,7 @@ fn getContextInternal() callconv(.naked) usize {...@@ -455,7 +463,7 @@ fn getContextInternal() callconv(.naked) usize {
455 [stack_offset] "i" (@offsetOf(ucontext_t, "stack")),463 [stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
456 [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),464 [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
457 [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")),465 [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")),
458 [sigset_size] "i" (linux.NSIG / 8),466 [sigset_size] "i" (@sizeOf(sigset_t)),
459 : "cc", "memory", "rax", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"467 : "cc", "memory", "rax", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"
460 );468 );
461}469}
lib/std/os/plan9.zig+4-1
...@@ -182,7 +182,6 @@ pub const SIG = struct {...@@ -182,7 +182,6 @@ pub const SIG = struct {
182 pub const TTOU = 20;182 pub const TTOU = 20;
183};183};
184pub const sigset_t = c_long;184pub const sigset_t = c_long;
185pub const empty_sigset = 0;
186pub const siginfo_t = c_long;185pub const siginfo_t = c_long;
187// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we include it here to be compatible.186// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we include it here to be compatible.
188pub const Sigaction = extern struct {187pub const Sigaction = extern struct {
...@@ -199,6 +198,10 @@ pub const Sigaction = extern struct {...@@ -199,6 +198,10 @@ pub const Sigaction = extern struct {
199pub const AT = struct {198pub const AT = struct {
200 pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9199 pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
201};200};
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}
202// TODO implement sigaction205// TODO implement sigaction
203// right now it is just a shim to allow using start.zig code206// right now it is just a shim to allow using start.zig code
204pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {207pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
lib/std/posix.zig+69-18
...@@ -86,6 +86,7 @@ pub const MREMAP = system.MREMAP;...@@ -86,6 +86,7 @@ pub const MREMAP = system.MREMAP;
86pub const MSF = system.MSF;86pub const MSF = system.MSF;
87pub const MSG = system.MSG;87pub const MSG = system.MSG;
88pub const NAME_MAX = system.NAME_MAX;88pub const NAME_MAX = system.NAME_MAX;
89pub const NSIG = system.NSIG;
89pub const O = system.O;90pub const O = system.O;
90pub const PATH_MAX = system.PATH_MAX;91pub const PATH_MAX = system.PATH_MAX;
91pub const POLL = system.POLL;92pub const POLL = system.POLL;
...@@ -126,10 +127,8 @@ pub const timerfd_clockid_t = system.timerfd_clockid_t;...@@ -126,10 +127,8 @@ pub const timerfd_clockid_t = system.timerfd_clockid_t;
126pub const cpu_set_t = system.cpu_set_t;127pub const cpu_set_t = system.cpu_set_t;
127pub const dev_t = system.dev_t;128pub const dev_t = system.dev_t;
128pub const dl_phdr_info = system.dl_phdr_info;129pub const dl_phdr_info = system.dl_phdr_info;
129pub const empty_sigset = system.empty_sigset;
130pub const fd_t = system.fd_t;130pub const fd_t = system.fd_t;
131pub const file_obj = system.file_obj;131pub const file_obj = system.file_obj;
132pub const filled_sigset = system.filled_sigset;
133pub const gid_t = system.gid_t;132pub const gid_t = system.gid_t;
134pub const ifreq = system.ifreq;133pub const ifreq = system.ifreq;
135pub const ino_t = system.ino_t;134pub const ino_t = system.ino_t;
...@@ -678,7 +677,8 @@ pub fn abort() noreturn {...@@ -678,7 +677,8 @@ pub fn abort() noreturn {
678 raise(SIG.ABRT) catch {};677 raise(SIG.ABRT) catch {};
679678
680 // Disable all signal handlers.679 // Disable all signal handlers.
681 sigprocmask(SIG.BLOCK, &linux.all_mask, null);680 const filledset = linux.sigfillset();
681 sigprocmask(SIG.BLOCK, &filledset, null);
682682
683 // Only one thread may proceed to the rest of abort().683 // Only one thread may proceed to the rest of abort().
684 if (!builtin.single_threaded) {684 if (!builtin.single_threaded) {
...@@ -691,14 +691,15 @@ pub fn abort() noreturn {...@@ -691,14 +691,15 @@ pub fn abort() noreturn {
691 // Install default handler so that the tkill below will terminate.691 // Install default handler so that the tkill below will terminate.
692 const sigact = Sigaction{692 const sigact = Sigaction{
693 .handler = .{ .handler = SIG.DFL },693 .handler = .{ .handler = SIG.DFL },
694 .mask = empty_sigset,694 .mask = sigemptyset(),
695 .flags = 0,695 .flags = 0,
696 };696 };
697 sigaction(SIG.ABRT, &sigact, null);697 sigaction(SIG.ABRT, &sigact, null);
698698
699 _ = linux.tkill(linux.gettid(), SIG.ABRT);699 _ = linux.tkill(linux.gettid(), SIG.ABRT);
700700
701 const sigabrtmask: linux.sigset_t = [_]u32{0} ** 31 ++ [_]u32{1 << (SIG.ABRT - 1)};701 var sigabrtmask = sigemptyset();
702 sigaddset(&sigabrtmask, SIG.ABRT);
702 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);703 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
703704
704 // Beyond this point should be unreachable.705 // Beyond this point should be unreachable.
...@@ -723,18 +724,13 @@ pub fn raise(sig: u8) RaiseError!void {...@@ -723,18 +724,13 @@ pub fn raise(sig: u8) RaiseError!void {
723 }724 }
724725
725 if (native_os == .linux) {726 if (native_os == .linux) {
726 // https://git.musl-libc.org/cgit/musl/commit/?id=0bed7e0acfd34e3fb63ca0e4d99b7592571355a9727 // Block all signals so a `fork` (from a signal handler) between the gettid() and kill() syscalls
727 //728 // cannot trigger an extra, unexpected, inter-process signal. Signal paranoia inherited from Musl.
728 // Unlike musl, libc-less Zig std does not have any internal signals for implementation purposes, so we729 const filled = linux.sigfillset();
729 // need to block all signals on the assumption that any of them could potentially fork() in a handler.730 var orig: sigset_t = undefined;
730 var set: sigset_t = undefined;731 sigprocmask(SIG.BLOCK, &filled, &orig);
731 sigprocmask(SIG.BLOCK, &linux.all_mask, &set);732 const rc = linux.tkill(linux.gettid(), sig);
732733 sigprocmask(SIG.SETMASK, &orig, null);
733 const tid = linux.gettid();
734 const rc = linux.tkill(tid, sig);
735
736 // restore signal mask
737 sigprocmask(SIG.SETMASK, &set, null);
738734
739 switch (errno(rc)) {735 switch (errno(rc)) {
740 .SUCCESS => return,736 .SUCCESS => return,
...@@ -5818,8 +5814,63 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {...@@ -5818,8 +5814,63 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
5818 }5814 }
5819}5815}
58205816
5817/// Return a filled sigset_t.
5818pub fn sigfillset() sigset_t {
5819 if (builtin.link_libc) {
5820 var set: sigset_t = undefined;
5821 switch (errno(system.sigfillset(&set))) {
5822 .SUCCESS => return set,
5823 else => unreachable,
5824 }
5825 }
5826 return system.sigfillset();
5827}
5828
5829/// Return an empty sigset_t.
5830pub fn sigemptyset() sigset_t {
5831 if (builtin.link_libc) {
5832 var set: sigset_t = undefined;
5833 switch (errno(system.sigemptyset(&set))) {
5834 .SUCCESS => return set,
5835 else => unreachable,
5836 }
5837 }
5838 return system.sigemptyset();
5839}
5840
5841pub fn sigaddset(set: *sigset_t, sig: u8) void {
5842 if (builtin.link_libc) {
5843 switch (errno(system.sigaddset(set, sig))) {
5844 .SUCCESS => return,
5845 else => unreachable,
5846 }
5847 }
5848 system.sigaddset(set, sig);
5849}
5850
5851pub fn sigdelset(set: *sigset_t, sig: u8) void {
5852 if (builtin.link_libc) {
5853 switch (errno(system.sigdelset(set, sig))) {
5854 .SUCCESS => return,
5855 else => unreachable,
5856 }
5857 }
5858 system.sigdelset(set, sig);
5859}
5860
5861pub fn sigismember(set: *const sigset_t, sig: u8) bool {
5862 if (builtin.link_libc) {
5863 const rc = system.sigismember(set, sig);
5864 switch (errno(rc)) {
5865 .SUCCESS => return rc == 1,
5866 else => unreachable,
5867 }
5868 }
5869 return system.sigismember(set, sig);
5870}
5871
5821/// Examine and change a signal action.5872/// Examine and change a signal action.
5822pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) void {5873pub fn sigaction(sig: u8, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) void {
5823 switch (errno(system.sigaction(sig, act, oact))) {5874 switch (errno(system.sigaction(sig, act, oact))) {
5824 .SUCCESS => return,5875 .SUCCESS => return,
5825 // EINVAL means the signal is either invalid or some signal that cannot have its action5876 // EINVAL means the signal is either invalid or some signal that cannot have its action
lib/std/posix/test.zig+147-26
...@@ -859,12 +859,61 @@ test "shutdown socket" {...@@ -859,12 +859,61 @@ test "shutdown socket" {
859 std.net.Stream.close(.{ .handle = sock });859 std.net.Stream.close(.{ .handle = sock });
860}860}
861861
862test "sigaction" {862test "sigset empty/full" {
863 if (native_os == .wasi or native_os == .windows)
864 return error.SkipZigTest;
865
866 var set: posix.sigset_t = posix.sigemptyset();
867 for (1..posix.NSIG) |i| {
868 try expectEqual(false, posix.sigismember(&set, @truncate(i)));
869 }
870
871 // The C library can reserve some (unnamed) signals, so can't check the full
872 // NSIG set is defined, but just test a couple:
873 set = posix.sigfillset();
874 try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.CHLD)));
875 try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT)));
876}
877
878// Some signals (32 - 34 on glibc/musl) are not allowed to be added to a
879// sigset by the C library, so avoid testing them.
880fn reserved_signo(i: usize) bool {
881 return builtin.link_libc and (i >= 32 and i <= 34);
882}
883
884test "sigset add/del" {
863 if (native_os == .wasi or native_os == .windows)885 if (native_os == .wasi or native_os == .windows)
864 return error.SkipZigTest;886 return error.SkipZigTest;
865887
866 // https://github.com/ziglang/zig/issues/7427888 var sigset: posix.sigset_t = posix.sigemptyset();
867 if (native_os == .linux and builtin.target.cpu.arch == .x86)889
890 // See that none are set, then set each one, see that they're all set, then
891 // remove them all, and then see that none are set.
892 for (1..posix.NSIG) |i| {
893 try expectEqual(false, posix.sigismember(&sigset, @truncate(i)));
894 }
895 for (1..posix.NSIG) |i| {
896 if (!reserved_signo(i)) {
897 posix.sigaddset(&sigset, @truncate(i));
898 }
899 }
900 for (1..posix.NSIG) |i| {
901 if (!reserved_signo(i)) {
902 try expectEqual(true, posix.sigismember(&sigset, @truncate(i)));
903 }
904 }
905 for (1..posix.NSIG) |i| {
906 if (!reserved_signo(i)) {
907 posix.sigdelset(&sigset, @truncate(i));
908 }
909 }
910 for (1..posix.NSIG) |i| {
911 try expectEqual(false, posix.sigismember(&sigset, @truncate(i)));
912 }
913}
914
915test "sigaction" {
916 if (native_os == .wasi or native_os == .windows)
868 return error.SkipZigTest;917 return error.SkipZigTest;
869918
870 // https://github.com/ziglang/zig/issues/15381919 // https://github.com/ziglang/zig/issues/15381
...@@ -872,66 +921,138 @@ test "sigaction" {...@@ -872,66 +921,138 @@ test "sigaction" {
872 return error.SkipZigTest;921 return error.SkipZigTest;
873 }922 }
874923
924 const test_signo = posix.SIG.URG; // URG only because it is ignored by default in debuggers
925
875 const S = struct {926 const S = struct {
876 var handler_called_count: u32 = 0;927 var handler_called_count: u32 = 0;
877928
878 fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void {929 fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void {
879 _ = ctx_ptr;930 _ = ctx_ptr;
880 // Check that we received the correct signal.931 // Check that we received the correct signal.
881 switch (native_os) {932 const info_sig = switch (native_os) {
882 .netbsd => {933 .netbsd => info.info.signo,
883 if (sig == posix.SIG.USR1 and sig == info.info.signo)934 else => info.signo,
884 handler_called_count += 1;935 };
885 },936 if (sig == test_signo and sig == info_sig) {
886 else => {937 handler_called_count += 1;
887 if (sig == posix.SIG.USR1 and sig == info.signo)
888 handler_called_count += 1;
889 },
890 }938 }
891 }939 }
892 };940 };
893941
894 var sa: posix.Sigaction = .{942 var sa: posix.Sigaction = .{
895 .handler = .{ .sigaction = &S.handler },943 .handler = .{ .sigaction = &S.handler },
896 .mask = posix.empty_sigset,944 .mask = posix.sigemptyset(),
897 .flags = posix.SA.SIGINFO | posix.SA.RESETHAND,945 .flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
898 };946 };
947
899 var old_sa: posix.Sigaction = undefined;948 var old_sa: posix.Sigaction = undefined;
900949
901 // Install the new signal handler.950 // Install the new signal handler.
902 posix.sigaction(posix.SIG.USR1, &sa, null);951 posix.sigaction(test_signo, &sa, null);
903952
904 // Check that we can read it back correctly.953 // Check that we can read it back correctly.
905 posix.sigaction(posix.SIG.USR1, null, &old_sa);954 posix.sigaction(test_signo, null, &old_sa);
906 try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);955 try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);
907 try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0);956 try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0);
908957
909 // Invoke the handler.958 // Invoke the handler.
910 try posix.raise(posix.SIG.USR1);959 try posix.raise(test_signo);
911 try testing.expect(S.handler_called_count == 1);960 try testing.expectEqual(1, S.handler_called_count);
912961
913 // Check if passing RESETHAND correctly reset the handler to SIG_DFL962 // Check if passing RESETHAND correctly reset the handler to SIG_DFL
914 posix.sigaction(posix.SIG.USR1, null, &old_sa);963 posix.sigaction(test_signo, null, &old_sa);
915 try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler);964 try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler);
916965
917 // Reinstall the signal w/o RESETHAND and re-raise966 // Reinstall the signal w/o RESETHAND and re-raise
918 sa.flags = posix.SA.SIGINFO;967 sa.flags = posix.SA.SIGINFO;
919 posix.sigaction(posix.SIG.USR1, &sa, null);968 posix.sigaction(test_signo, &sa, null);
920 try posix.raise(posix.SIG.USR1);969 try posix.raise(test_signo);
921 try testing.expect(S.handler_called_count == 2);970 try testing.expectEqual(2, S.handler_called_count);
922971
923 // Now set the signal to ignored972 // Now set the signal to ignored
924 sa.handler = .{ .handler = posix.SIG.IGN };973 sa.handler = .{ .handler = posix.SIG.IGN };
925 sa.flags = 0;974 sa.flags = 0;
926 posix.sigaction(posix.SIG.USR1, &sa, null);975 posix.sigaction(test_signo, &sa, null);
927976
928 // Re-raise to ensure handler is actually ignored977 // Re-raise to ensure handler is actually ignored
929 try posix.raise(posix.SIG.USR1);978 try posix.raise(test_signo);
930 try testing.expect(S.handler_called_count == 2);979 try testing.expectEqual(2, S.handler_called_count);
931980
932 // Ensure that ignored state is returned when querying981 // Ensure that ignored state is returned when querying
933 posix.sigaction(posix.SIG.USR1, null, &old_sa);982 posix.sigaction(test_signo, null, &old_sa);
934 try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler.?);983 try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler);
984}
985
986test "sigset_t bits" {
987 if (native_os == .wasi or native_os == .windows)
988 return error.SkipZigTest;
989
990 const S = struct {
991 var expected_sig: i32 = undefined;
992 var handler_called_count: u32 = 0;
993
994 fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void {
995 _ = ctx_ptr;
996
997 const info_sig = switch (native_os) {
998 .netbsd => info.info.signo,
999 else => info.signo,
1000 };
1001 if (sig == expected_sig and sig == info_sig) {
1002 handler_called_count += 1;
1003 }
1004 }
1005 };
1006
1007 const self_pid = posix.system.getpid();
1008
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| {
1014 if (test_signo >= posix.NSIG) continue;
1015
1016 S.expected_sig = test_signo;
1017 S.handler_called_count = 0;
1018
1019 const sa: posix.Sigaction = .{
1020 .handler = .{ .sigaction = &S.handler },
1021 .mask = posix.sigemptyset(),
1022 .flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
1023 };
1024
1025 var old_sa: posix.Sigaction = undefined;
1026
1027 // Install the new signal handler.
1028 posix.sigaction(test_signo, &sa, &old_sa);
1029
1030 // block the signal and see that its delayed until unblocked
1031 var block_one: posix.sigset_t = posix.sigemptyset();
1032 posix.sigaddset(&block_one, test_signo);
1033 posix.sigprocmask(posix.SIG.BLOCK, &block_one, null);
1034
1035 // qemu maps target signals to host signals 1-to-1, so targets
1036 // with more signals than the host will fail to send the signal.
1037 const rc = posix.system.kill(self_pid, test_signo);
1038 switch (posix.errno(rc)) {
1039 .SUCCESS => {
1040 // See that the signal is blocked, then unblocked
1041 try testing.expectEqual(0, S.handler_called_count);
1042 posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null);
1043 try testing.expectEqual(1, S.handler_called_count);
1044 },
1045 .INVAL => {
1046 // Signal won't get delviered. Just clean up.
1047 posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null);
1048 try testing.expectEqual(0, S.handler_called_count);
1049 },
1050 else => |errno| return posix.unexpectedErrno(errno),
1051 }
1052
1053 // Restore original handler
1054 posix.sigaction(test_signo, &old_sa, null);
1055 }
935}1056}
9361057
937test "dup & dup2" {1058test "dup & dup2" {
lib/std/start.zig+1-1
...@@ -749,7 +749,7 @@ fn maybeIgnoreSigpipe() void {...@@ -749,7 +749,7 @@ fn maybeIgnoreSigpipe() void {
749 // Set handler to a noop function instead of `SIG.IGN` to prevent749 // Set handler to a noop function instead of `SIG.IGN` to prevent
750 // leaking signal disposition to a child process.750 // leaking signal disposition to a child process.
751 .handler = .{ .handler = noopSigHandler },751 .handler = .{ .handler = noopSigHandler },
752 .mask = posix.empty_sigset,752 .mask = posix.sigemptyset(),
753 .flags = 0,753 .flags = 0,
754 };754 };
755 posix.sigaction(posix.SIG.PIPE, &act, null);755 posix.sigaction(posix.SIG.PIPE, &act, null);
src/crash_report.zig+2-3
...@@ -175,12 +175,11 @@ pub fn attachSegfaultHandler() void {...@@ -175,12 +175,11 @@ pub fn attachSegfaultHandler() void {
175 _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);175 _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
176 return;176 return;
177 }177 }
178 var act: posix.Sigaction = .{178 const act: posix.Sigaction = .{
179 .handler = .{ .sigaction = handleSegfaultPosix },179 .handler = .{ .sigaction = handleSegfaultPosix },
180 .mask = posix.empty_sigset,180 .mask = posix.sigemptyset(),
181 .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),181 .flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
182 };182 };
183
184 debug.updateSegfaultHandler(&act);183 debug.updateSegfaultHandler(&act);
185}184}
186185
test/standalone/sigpipe/build.zig+1-1
...@@ -18,7 +18,7 @@ pub fn build(b: *std.build.Builder) !void {...@@ -18,7 +18,7 @@ pub fn build(b: *std.build.Builder) !void {
18 {18 {
19 const act = posix.Sigaction{19 const act = posix.Sigaction{
20 .handler = .{ .handler = posix.SIG.DFL },20 .handler = .{ .handler = posix.SIG.DFL },
21 .mask = posix.empty_sigset,21 .mask = posix.sigemptyset(),
22 .flags = 0,22 .flags = 0,
23 };23 };
24 try posix.sigaction(posix.SIG.PIPE, &act, null);24 try posix.sigaction(posix.SIG.PIPE, &act, null);