Commit 6eb5e56306

Pat Tullmann <pat.github@tullmann.org>
2025-04-29 06:03:23
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
1 parent 85a6b75
Changed files (4)
lib/std/os/linux.zig
@@ -1801,6 +1801,19 @@ const SigsetElement = c_ulong;
 
 const sigset_len = @typeInfo(sigset_t).array.len;
 
+/// Zig's SIGRTMIN, but is a function for compatibility with glibc
+pub fn sigrtmin() u8 {
+    // Default is 32 in the kernel UAPI: https://github.com/torvalds/linux/blob/78109c591b806e41987e0b83390e61d675d1f724/include/uapi/asm-generic/signal.h#L50
+    // AFAICT, all architectures that override this also set it to 32:
+    // https://github.com/search?q=repo%3Atorvalds%2Flinux+sigrtmin+path%3Auapi&type=code
+    return 32;
+}
+
+/// Zig's SIGRTMAX, but is a function for compatibility with glibc
+pub fn sigrtmax() u8 {
+    return NSIG - 1;
+}
+
 /// Zig's version of sigemptyset.  Returns initialized sigset_t.
 pub fn sigemptyset() sigset_t {
     return [_]SigsetElement{0} ** sigset_len;
lib/std/posix/test.zig
@@ -859,6 +859,17 @@ test "shutdown socket" {
     std.net.Stream.close(.{ .handle = sock });
 }
 
+test "sigrtmin/max" {
+    if (native_os == .wasi or native_os == .windows or native_os == .macos) {
+        return error.SkipZigTest;
+    }
+
+    try std.testing.expect(posix.sigrtmin() >= 32);
+    try std.testing.expect(posix.sigrtmin() >= posix.system.sigrtmin());
+    try std.testing.expect(posix.sigrtmin() < posix.system.sigrtmax());
+    try std.testing.expect(posix.sigrtmax() < posix.NSIG);
+}
+
 test "sigset empty/full" {
     if (native_os == .wasi or native_os == .windows)
         return error.SkipZigTest;
@@ -875,10 +886,13 @@ test "sigset empty/full" {
     try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT)));
 }
 
-// Some signals (32 - 34 on glibc/musl) are not allowed to be added to a
+// Some signals (i.e., 32 - 34 on glibc/musl) are not allowed to be added to a
 // sigset by the C library, so avoid testing them.
 fn reserved_signo(i: usize) bool {
-    return builtin.link_libc and (i >= 32 and i <= 34);
+    if (native_os == .macos) {
+        return false;
+    }
+    return builtin.link_libc and (i >= 32 and i < posix.sigrtmin());
 }
 
 test "sigset add/del" {
lib/std/c.zig
@@ -10347,6 +10347,16 @@ pub const sigaction = switch (native_os) {
     else => private.sigaction,
 };
 
+/// Zig's version of SIGRTMIN.  Actually a function.
+pub fn sigrtmin() u8 {
+    return @truncate(@as(c_uint, @bitCast(private.__libc_current_sigrtmin())));
+}
+
+/// Zig's version of SIGRTMAX.  Actually a function.
+pub fn sigrtmax() u8 {
+    return @truncate(@as(c_uint, @bitCast(private.__libc_current_sigrtmax())));
+}
+
 pub const sigfillset = switch (native_os) {
     .netbsd => private.__sigfillset14,
     else => private.sigfillset,
@@ -11213,6 +11223,9 @@ const private = struct {
     extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
     extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
 
+    extern "c" fn __libc_current_sigrtmin() c_int;
+    extern "c" fn __libc_current_sigrtmax() c_int;
+
     // Don't forget to add another clown when an OS picks yet another unique
     // symbol name for errno location!
     // 🤡🤡🤡🤡🤡🤡
lib/std/posix.zig
@@ -151,6 +151,8 @@ pub const rusage = system.rusage;
 pub const sa_family_t = system.sa_family_t;
 pub const siginfo_t = system.siginfo_t;
 pub const sigset_t = system.sigset_t;
+pub const sigrtmin = system.sigrtmin;
+pub const sigrtmax = system.sigrtmax;
 pub const sockaddr = system.sockaddr;
 pub const socklen_t = system.socklen_t;
 pub const stack_t = system.stack_t;