authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-12-12 13:57:25+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-12-12 13:57:25+01:00
logbeae3cea178a0a93c25164e992e01c7b5b78e4d7
tree71deda4290771d8d710abfbbbc9158016eabc4ea
parentd569e37cb538d17d009f5632c25acd643d3736cb

std: Improve sigaction interface

Add a smoke test to prevent regressions.

5 files changed, 64 insertions(+), 27 deletions(-)

lib/std/c.zig+3-3
...@@ -200,7 +200,7 @@ pub usingnamespace switch (builtin.os.tag) {...@@ -200,7 +200,7 @@ pub usingnamespace switch (builtin.os.tag) {
200 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;200 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
201 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;201 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
202 pub extern "c" fn sched_yield() c_int;202 pub extern "c" fn sched_yield() c_int;
203 pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;203 pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
204 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;204 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
205 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;205 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
206 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;206 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) {...@@ -215,7 +215,7 @@ pub usingnamespace switch (builtin.os.tag) {
215 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;215 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
216 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;216 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
217 pub extern "c" fn sched_yield() c_int;217 pub extern "c" fn sched_yield() c_int;
218 pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;218 pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
219 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;219 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
220 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;220 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
221 },221 },
...@@ -227,7 +227,7 @@ pub usingnamespace switch (builtin.os.tag) {...@@ -227,7 +227,7 @@ pub usingnamespace switch (builtin.os.tag) {
227 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;227 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
228 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;228 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
229 pub extern "c" fn sched_yield() c_int;229 pub extern "c" fn sched_yield() c_int;
230 pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;230 pub extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
231 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;231 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
232 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;232 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
233 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;233 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
lib/std/os.zig+1-1
...@@ -4592,7 +4592,7 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {...@@ -4592,7 +4592,7 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
4592}4592}
45934593
4594/// Examine and change a signal action.4594/// Examine and change a signal action.
4595pub fn sigaction(sig: u6, act: *const Sigaction, oact: ?*Sigaction) void {4595pub fn sigaction(sig: u6, act: ?*const Sigaction, oact: ?*Sigaction) void {
4596 switch (errno(system.sigaction(sig, act, oact))) {4596 switch (errno(system.sigaction(sig, act, oact))) {
4597 0 => return,4597 0 => return,
4598 EFAULT => unreachable,4598 EFAULT => unreachable,
lib/std/os/bits/linux.zig+3-3
...@@ -867,13 +867,13 @@ pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffff...@@ -867,13 +867,13 @@ pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffff
867pub const k_sigaction = if (is_mips)867pub const k_sigaction = if (is_mips)
868 extern struct {868 extern struct {
869 flags: usize,869 flags: usize,
870 sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void,870 sigaction: ?fn (i32, *const siginfo_t, ?*const c_void) callconv(.C) void,
871 mask: [4]u32,871 mask: [4]u32,
872 restorer: fn () callconv(.C) void,872 restorer: fn () callconv(.C) void,
873 }873 }
874else874else
875 extern struct {875 extern struct {
876 sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void,876 sigaction: ?fn (i32, *const siginfo_t, ?*const c_void) callconv(.C) void,
877 flags: usize,877 flags: usize,
878 restorer: fn () callconv(.C) void,878 restorer: fn () callconv(.C) void,
879 mask: [2]u32,879 mask: [2]u32,
...@@ -881,7 +881,7 @@ else...@@ -881,7 +881,7 @@ else
881881
882/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.882/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
883pub const Sigaction = extern struct {883pub const Sigaction = extern struct {
884 pub const sigaction_fn = fn (i32, *siginfo_t, ?*c_void) callconv(.C) void;884 pub const sigaction_fn = fn (i32, *const siginfo_t, ?*const c_void) callconv(.C) void;
885 sigaction: ?sigaction_fn,885 sigaction: ?sigaction_fn,
886 mask: sigset_t,886 mask: sigset_t,
887 flags: u32,887 flags: u32,
lib/std/os/linux.zig+27-20
...@@ -857,35 +857,42 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*...@@ -857,35 +857,42 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*
857 return syscall4(.rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);857 return syscall4(.rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
858}858}
859859
860pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {860pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
861 assert(sig >= 1);861 assert(sig >= 1);
862 assert(sig != SIGKILL);862 assert(sig != SIGKILL);
863 assert(sig != SIGSTOP);863 assert(sig != SIGSTOP);
864864
865 const restorer_fn = if ((act.flags & SA_SIGINFO) != 0) restore_rt else restore;865 var ksa: k_sigaction = undefined;
866 var ksa = k_sigaction{866 var oldksa: k_sigaction = undefined;
867 .sigaction = act.sigaction,867 const mask_size = @sizeOf(@TypeOf(ksa.mask));
868 .flags = act.flags | SA_RESTORER,868
869 .mask = undefined,869 if (act) |new| {
870 .restorer = @ptrCast(fn () callconv(.C) void, restorer_fn),870 const restorer_fn = if ((new.flags & SA_SIGINFO) != 0) restore_rt else restore;
871 };871 ksa = k_sigaction{
872 var ksa_old: k_sigaction = undefined;872 .sigaction = new.sigaction,
873 const ksa_mask_size = @sizeOf(@TypeOf(ksa_old.mask));873 .flags = new.flags | SA_RESTORER,
874 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), ksa_mask_size);874 .mask = undefined,
875 .restorer = @ptrCast(fn () callconv(.C) void, restorer_fn),
876 };
877 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &new.mask), mask_size);
878 }
879
880 const ksa_arg = if (act != null) @ptrToInt(&ksa) else 0;
881 const oldksa_arg = if (oact != null) @ptrToInt(&oldksa) else 0;
882
875 const result = switch (builtin.arch) {883 const result = switch (builtin.arch) {
876 // The sparc version of rt_sigaction needs the restorer function to be passed as an argument too.884 // The sparc version of rt_sigaction needs the restorer function to be passed as an argument too.
877 .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @ptrToInt(ksa.restorer), ksa_mask_size),885 .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @ptrToInt(ksa.restorer), mask_size),
878 else => syscall4(.rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), ksa_mask_size),886 else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size),
879 };887 };
880 const err = getErrno(result);888 if (getErrno(result) != 0) return result;
881 if (err != 0) {889
882 return result;
883 }
884 if (oact) |old| {890 if (oact) |old| {
885 old.sigaction = ksa_old.sigaction;891 old.sigaction = oldksa.sigaction;
886 old.flags = @truncate(u32, ksa_old.flags);892 old.flags = @truncate(u32, oldksa.flags);
887 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), ksa_mask_size);893 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &oldksa.mask), mask_size);
888 }894 }
895
889 return 0;896 return 0;
890}897}
891898
lib/std/os/test.zig+30
...@@ -646,3 +646,33 @@ test "shutdown socket" {...@@ -646,3 +646,33 @@ test "shutdown socket" {
646 };646 };
647 os.closeSocket(sock);647 os.closeSocket(sock);
648}648}
649
650var signal_test_failed = true;
651
652test "sigaction" {
653 if (builtin.os.tag == .wasi or builtin.os.tag == .windows)
654 return error.SkipZigTest;
655
656 const S = struct {
657 fn handler(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void {
658 // Check that we received the correct signal.
659 signal_test_failed = info.signo == os.SIGUSR1;
660 }
661 };
662
663 var sa = os.Sigaction{
664 .sigaction = S.handler,
665 .mask = os.empty_sigset,
666 .flags = os.SA_RESETHAND,
667 };
668 var old_sa: os.Sigaction = undefined;
669 // Install the new signal handler.
670 os.sigaction(os.SIGUSR1, &sa, null);
671 // Check that we can read it back correctly.
672 os.sigaction(os.SIGUSR1, null, &old_sa);
673 testing.expectEqual(S.handler, old_sa.sigaction.?);
674 testing.expect((old_sa.flags & os.SA_RESETHAND) != 0);
675 // Invoke the handler.
676 try os.raise(os.SIGUSR1);
677 testing.expect(signal_test_failed == false);
678}