diff --git a/lib/std/c.zig b/lib/std/c.zig index 5ebbb9dd22..a8ac19053d 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -200,7 +200,7 @@ pub usingnamespace switch (builtin.os.tag) { pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; pub extern "c" fn sched_yield() c_int; - pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; + pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int; @@ -215,7 +215,7 @@ pub usingnamespace switch (builtin.os.tag) { pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; pub extern "c" fn sched_yield() c_int; - pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; + pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int; }, @@ -227,7 +227,7 @@ pub usingnamespace switch (builtin.os.tag) { pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; pub extern "c" fn sched_yield() c_int; - pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; + pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int; diff --git a/lib/std/os.zig b/lib/std/os.zig index e3afe90e5d..b385ffa19f 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4592,7 +4592,7 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { } /// Examine and change a signal action. -pub fn sigaction(sig: u6, act: *const Sigaction, oact: ?*Sigaction) void { +pub fn sigaction(sig: u6, act: ?*const Sigaction, oact: ?*Sigaction) void { switch (errno(system.sigaction(sig, act, oact))) { 0 => return, EFAULT => unreachable, diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 6952ab7e0e..72621b7fee 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -867,13 +867,13 @@ pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffff pub const k_sigaction = if (is_mips) extern struct { flags: usize, - sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void, + sigaction: ?fn (i32, *const siginfo_t, ?*const c_void) callconv(.C) void, mask: [4]u32, restorer: fn () callconv(.C) void, } else extern struct { - sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void, + sigaction: ?fn (i32, *const siginfo_t, ?*const c_void) callconv(.C) void, flags: usize, restorer: fn () callconv(.C) void, mask: [2]u32, @@ -881,7 +881,7 @@ else /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const sigaction_fn = fn (i32, *siginfo_t, ?*c_void) callconv(.C) void; + pub const sigaction_fn = fn (i32, *const siginfo_t, ?*const c_void) callconv(.C) void; sigaction: ?sigaction_fn, mask: sigset_t, flags: u32, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index b669ed2436..956d92da36 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -857,35 +857,42 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?* return syscall4(.rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8); } -pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { +pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize { assert(sig >= 1); assert(sig != SIGKILL); assert(sig != SIGSTOP); - const restorer_fn = if ((act.flags & SA_SIGINFO) != 0) restore_rt else restore; - var ksa = k_sigaction{ - .sigaction = act.sigaction, - .flags = act.flags | SA_RESTORER, - .mask = undefined, - .restorer = @ptrCast(fn () callconv(.C) void, restorer_fn), - }; - var ksa_old: k_sigaction = undefined; - const ksa_mask_size = @sizeOf(@TypeOf(ksa_old.mask)); - @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), ksa_mask_size); + var ksa: k_sigaction = undefined; + var oldksa: k_sigaction = undefined; + const mask_size = @sizeOf(@TypeOf(ksa.mask)); + + if (act) |new| { + const restorer_fn = if ((new.flags & SA_SIGINFO) != 0) restore_rt else restore; + ksa = k_sigaction{ + .sigaction = new.sigaction, + .flags = new.flags | SA_RESTORER, + .mask = undefined, + .restorer = @ptrCast(fn () callconv(.C) void, restorer_fn), + }; + @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &new.mask), mask_size); + } + + const ksa_arg = if (act != null) @ptrToInt(&ksa) else 0; + const oldksa_arg = if (oact != null) @ptrToInt(&oldksa) else 0; + const result = switch (builtin.arch) { // The sparc version of rt_sigaction needs the restorer function to be passed as an argument too. - .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @ptrToInt(ksa.restorer), ksa_mask_size), - else => syscall4(.rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), ksa_mask_size), + .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @ptrToInt(ksa.restorer), mask_size), + else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size), }; - const err = getErrno(result); - if (err != 0) { - return result; - } + if (getErrno(result) != 0) return result; + if (oact) |old| { - old.sigaction = ksa_old.sigaction; - old.flags = @truncate(u32, ksa_old.flags); - @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), ksa_mask_size); + old.sigaction = oldksa.sigaction; + old.flags = @truncate(u32, oldksa.flags); + @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &oldksa.mask), mask_size); } + return 0; } diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 81f9922d13..be0c718086 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -646,3 +646,33 @@ test "shutdown socket" { }; os.closeSocket(sock); } + +var signal_test_failed = true; + +test "sigaction" { + if (builtin.os.tag == .wasi or builtin.os.tag == .windows) + return error.SkipZigTest; + + const S = struct { + fn handler(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void { + // Check that we received the correct signal. + signal_test_failed = info.signo == os.SIGUSR1; + } + }; + + var sa = os.Sigaction{ + .sigaction = S.handler, + .mask = os.empty_sigset, + .flags = os.SA_RESETHAND, + }; + var old_sa: os.Sigaction = undefined; + // Install the new signal handler. + os.sigaction(os.SIGUSR1, &sa, null); + // Check that we can read it back correctly. + os.sigaction(os.SIGUSR1, null, &old_sa); + testing.expectEqual(S.handler, old_sa.sigaction.?); + testing.expect((old_sa.flags & os.SA_RESETHAND) != 0); + // Invoke the handler. + try os.raise(os.SIGUSR1); + testing.expect(signal_test_failed == false); +}