authorgravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2025-04-28 21:03:23-07:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-09 15:10:25+02:00
log6eb5e56306620e72ae80d7ad6626f8d0ceb24af5
tree2ca4383369165a41814d3b95f148e86f46627920
parent85a6b75e18248bad83437323cab14fe1973057ec

std.posix: Add sigrtmin() and sigrtmax()

For C code the macros SIGRTMIN and SIGRTMAX provide these values. In practice what looks like a constant is actually provided by a libc call. So the Zig implementations are explicitly function calls. glibc (and Musl) export a run-time minimum "real-time" signal number, based on how many signals are reserved for internal implementation details (generally threading). In practice, on Linux, sigrtmin() is 35 on glibc with the older LinuxThread and 34 with the newer NPTL-based implementation. Musl always returns 35. The maximum "real-time" signal number is NSIG - 1 (64 on most Linux kernels, but 128 on MIPS). When not linking a C Library, Zig can report the full range of "rt" signals (none are reserved by Zig). Fixes #21189

4 files changed, 44 insertions(+), 2 deletions(-)

lib/std/c.zig+13
......@@ -10347,6 +10347,16 @@ pub const sigaction = switch (native_os) {
1034710347 else => private.sigaction,
1034810348};
1034910349
10350/// Zig's version of SIGRTMIN. Actually a function.
10351pub fn sigrtmin() u8 {
10352 return @truncate(@as(c_uint, @bitCast(private.__libc_current_sigrtmin())));
10353}
10354
10355/// Zig's version of SIGRTMAX. Actually a function.
10356pub fn sigrtmax() u8 {
10357 return @truncate(@as(c_uint, @bitCast(private.__libc_current_sigrtmax())));
10358}
10359
1035010360pub const sigfillset = switch (native_os) {
1035110361 .netbsd => private.__sigfillset14,
1035210362 else => private.sigfillset,
......@@ -11213,6 +11223,9 @@ const private = struct {
1121311223 extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
1121411224 extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
1121511225
11226 extern "c" fn __libc_current_sigrtmin() c_int;
11227 extern "c" fn __libc_current_sigrtmax() c_int;
11228
1121611229 // Don't forget to add another clown when an OS picks yet another unique
1121711230 // symbol name for errno location!
1121811231 // 🤡🤡🤡🤡🤡🤡
lib/std/os/linux.zig+13
......@@ -1801,6 +1801,19 @@ const SigsetElement = c_ulong;
18011801
18021802const sigset_len = @typeInfo(sigset_t).array.len;
18031803
1804/// Zig's SIGRTMIN, but is a function for compatibility with glibc
1805pub fn sigrtmin() u8 {
1806 // Default is 32 in the kernel UAPI: https://github.com/torvalds/linux/blob/78109c591b806e41987e0b83390e61d675d1f724/include/uapi/asm-generic/signal.h#L50
1807 // AFAICT, all architectures that override this also set it to 32:
1808 // https://github.com/search?q=repo%3Atorvalds%2Flinux+sigrtmin+path%3Auapi&type=code
1809 return 32;
1810}
1811
1812/// Zig's SIGRTMAX, but is a function for compatibility with glibc
1813pub fn sigrtmax() u8 {
1814 return NSIG - 1;
1815}
1816
18041817/// Zig's version of sigemptyset. Returns initialized sigset_t.
18051818pub fn sigemptyset() sigset_t {
18061819 return [_]SigsetElement{0} ** sigset_len;
lib/std/posix.zig+2
......@@ -151,6 +151,8 @@ pub const rusage = system.rusage;
151151pub const sa_family_t = system.sa_family_t;
152152pub const siginfo_t = system.siginfo_t;
153153pub const sigset_t = system.sigset_t;
154pub const sigrtmin = system.sigrtmin;
155pub const sigrtmax = system.sigrtmax;
154156pub const sockaddr = system.sockaddr;
155157pub const socklen_t = system.socklen_t;
156158pub const stack_t = system.stack_t;
lib/std/posix/test.zig+16-2
......@@ -859,6 +859,17 @@ test "shutdown socket" {
859859 std.net.Stream.close(.{ .handle = sock });
860860}
861861
862test "sigrtmin/max" {
863 if (native_os == .wasi or native_os == .windows or native_os == .macos) {
864 return error.SkipZigTest;
865 }
866
867 try std.testing.expect(posix.sigrtmin() >= 32);
868 try std.testing.expect(posix.sigrtmin() >= posix.system.sigrtmin());
869 try std.testing.expect(posix.sigrtmin() < posix.system.sigrtmax());
870 try std.testing.expect(posix.sigrtmax() < posix.NSIG);
871}
872
862873test "sigset empty/full" {
863874 if (native_os == .wasi or native_os == .windows)
864875 return error.SkipZigTest;
......@@ -875,10 +886,13 @@ test "sigset empty/full" {
875886 try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT)));
876887}
877888
878// Some signals (32 - 34 on glibc/musl) are not allowed to be added to a
889// Some signals (i.e., 32 - 34 on glibc/musl) are not allowed to be added to a
879890// sigset by the C library, so avoid testing them.
880891fn reserved_signo(i: usize) bool {
881 return builtin.link_libc and (i >= 32 and i <= 34);
892 if (native_os == .macos) {
893 return false;
894 }
895 return builtin.link_libc and (i >= 32 and i < posix.sigrtmin());
882896}
883897
884898test "sigset add/del" {