authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-14 17:16:55+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-12-14 17:16:55+01:00
log91e8be385cdcc53bb8703f317e6f1f7fd4239e4f
tree15ea052a2567d9eb9acd8bc3c778bacc9522830f
parenta471a57560401c5562c4dc3e588227b689bf9487
parentd9e9390550e8290c1959ad2a8940e94d56f3ae1e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7411 from LemonBoy/sigaction-smoke

std: Improve sigaction interface

11 files changed, 219 insertions(+), 72 deletions(-)

lib/std/c.zig+3-3
......@@ -200,7 +200,7 @@ pub usingnamespace switch (builtin.os.tag) {
200200 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
201201 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
202202 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;
204204 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
205205 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
206206 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) {
215215 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
216216 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
217217 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;
219219 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
220220 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
221221 },
......@@ -227,7 +227,7 @@ pub usingnamespace switch (builtin.os.tag) {
227227 pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
228228 pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
229229 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;
231231 pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
232232 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
233233 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
lib/std/debug.zig+2-2
......@@ -1721,7 +1721,7 @@ pub fn attachSegfaultHandler() void {
17211721 return;
17221722 }
17231723 var act = os.Sigaction{
1724 .sigaction = handleSegfaultLinux,
1724 .handler = .{ .sigaction = handleSegfaultLinux },
17251725 .mask = os.empty_sigset,
17261726 .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
17271727 };
......@@ -1740,7 +1740,7 @@ fn resetSegfaultHandler() void {
17401740 return;
17411741 }
17421742 var act = os.Sigaction{
1743 .sigaction = os.SIG_DFL,
1743 .handler = .{ .sigaction = os.SIG_DFL },
17441744 .mask = os.empty_sigset,
17451745 .flags = 0,
17461746 };
lib/std/os.zig+1-1
......@@ -4592,7 +4592,7 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
45924592}
45934593
45944594/// 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 {
45964596 switch (errno(system.sigaction(sig, act, oact))) {
45974597 0 => return,
45984598 EFAULT => unreachable,
lib/std/os/bits/darwin.zig+31-4
......@@ -124,13 +124,40 @@ pub const timespec = extern struct {
124124};
125125
126126pub const sigset_t = u32;
127pub const empty_sigset = sigset_t(0);
127pub const empty_sigset: sigset_t = 0;
128
129pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
130pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
131pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
132pub const SIG_HOLD = @intToPtr(?Sigaction.sigaction_fn, 5);
133
134pub const siginfo_t = extern struct {
135 signo: c_int,
136 errno: c_int,
137 code: c_int,
138 pid: pid_t,
139 uid: uid_t,
140 status: c_int,
141 addr: *c_void,
142 value: extern union {
143 int: c_int,
144 ptr: *c_void,
145 },
146 si_band: c_long,
147 _pad: [7]c_ulong,
148};
128149
129150/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
130151pub const Sigaction = extern struct {
131 handler: fn (c_int) callconv(.C) void,
132 sa_mask: sigset_t,
133 sa_flags: c_int,
152 pub const handler_fn = fn (c_int) callconv(.C) void;
153 pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void;
154
155 handler: extern union {
156 handler: ?handler_fn,
157 sigaction: ?sigaction_fn,
158 },
159 mask: sigset_t,
160 flags: c_uint,
134161};
135162
136163pub const dirent = extern struct {
lib/std/os/bits/dragonfly.zig+9-5
......@@ -530,12 +530,16 @@ pub const sigset_t = extern struct {
530530};
531531pub const sig_atomic_t = c_int;
532532pub const Sigaction = extern struct {
533 __sigaction_u: extern union {
534 __sa_handler: ?fn (c_int) callconv(.C) void,
535 __sa_sigaction: ?fn (c_int, [*c]siginfo_t, ?*c_void) callconv(.C) void,
533 pub const handler_fn = fn (c_int) callconv(.C) void;
534 pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void;
535
536 /// signal handler
537 handler: extern union {
538 handler: ?handler_fn,
539 sigaction: ?sigaction_fn,
536540 },
537 sa_flags: c_int,
538 sa_mask: sigset_t,
541 flags: c_uint,
542 mask: sigset_t,
539543};
540544pub const sig_t = [*c]fn (c_int) callconv(.C) void;
541545
lib/std/os/bits/freebsd.zig+48-8
......@@ -736,23 +736,61 @@ pub const winsize = extern struct {
736736
737737const NSIG = 32;
738738
739pub const SIG_ERR = @intToPtr(fn (i32) callconv(.C) void, maxInt(usize));
740pub const SIG_DFL = @intToPtr(fn (i32) callconv(.C) void, 0);
741pub const SIG_IGN = @intToPtr(fn (i32) callconv(.C) void, 1);
739pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
740pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
741pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
742742
743743/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
744744pub const Sigaction = extern struct {
745 pub const handler_fn = fn (c_int) callconv(.C) void;
746 pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void;
747
745748 /// signal handler
746 __sigaction_u: extern union {
747 __sa_handler: fn (i32) callconv(.C) void,
748 __sa_sigaction: fn (i32, *__siginfo, usize) callconv(.C) void,
749 handler: extern union {
750 handler: ?handler_fn,
751 sigaction: ?sigaction_fn,
749752 },
750753
751754 /// see signal options
752 sa_flags: u32,
755 flags: c_uint,
753756
754757 /// signal mask to apply
755 sa_mask: sigset_t,
758 mask: sigset_t,
759};
760
761pub const siginfo_t = extern struct {
762 signo: c_int,
763 errno: c_int,
764 code: c_int,
765 pid: pid_t,
766 uid: uid_t,
767 status: c_int,
768 addr: ?*c_void,
769 value: sigval,
770 reason: extern union {
771 fault: extern struct {
772 trapno: c_int,
773 },
774 timer: extern struct {
775 timerid: c_int,
776 overrun: c_int,
777 },
778 mesgq: extern struct {
779 mqd: c_int,
780 },
781 poll: extern struct {
782 band: c_long,
783 },
784 spare: extern struct {
785 spare1: c_long,
786 spare2: [7]c_int,
787 },
788 },
789};
790
791pub const sigval = extern union {
792 int: c_int,
793 ptr: ?*c_void,
756794};
757795
758796pub const _SIG_WORDS = 4;
......@@ -775,6 +813,8 @@ pub const sigset_t = extern struct {
775813 __bits: [_SIG_WORDS]u32,
776814};
777815
816pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS };
817
778818pub const EPERM = 1; // Operation not permitted
779819pub const ENOENT = 2; // No such file or directory
780820pub const ESRCH = 3; // No such process
lib/std/os/bits/linux.zig+26-15
......@@ -864,27 +864,38 @@ pub const sigset_t = [1024 / 32]u32;
864864pub const all_mask: sigset_t = [_]u32{0xffffffff} ** sigset_t.len;
865865pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
866866
867pub const k_sigaction = if (is_mips)
868 extern struct {
869 flags: usize,
870 sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void,
871 mask: [4]u32,
867pub const k_sigaction = switch (builtin.arch) {
868 .mips, .mipsel => extern struct {
869 flags: c_uint,
870 handler: ?fn (c_int) callconv(.C) void,
871 mask: [4]c_ulong,
872872 restorer: fn () callconv(.C) void,
873 }
874else
875 extern struct {
876 sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void,
877 flags: usize,
873 },
874 .mips64, .mips64el => extern struct {
875 flags: c_uint,
876 handler: ?fn (c_int) callconv(.C) void,
877 mask: [2]c_ulong,
878878 restorer: fn () callconv(.C) void,
879 mask: [2]u32,
880 };
879 },
880 else => extern struct {
881 handler: ?fn (c_int) callconv(.C) void,
882 flags: c_ulong,
883 restorer: fn () callconv(.C) void,
884 mask: [2]c_uint,
885 },
886};
881887
882888/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
883889pub const Sigaction = extern struct {
884 pub const sigaction_fn = fn (i32, *siginfo_t, ?*c_void) callconv(.C) void;
885 sigaction: ?sigaction_fn,
890 pub const handler_fn = fn (c_int) callconv(.C) void;
891 pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void;
892
893 handler: extern union {
894 handler: ?handler_fn,
895 sigaction: ?sigaction_fn,
896 },
886897 mask: sigset_t,
887 flags: u32,
898 flags: c_uint,
888899 restorer: ?fn () callconv(.C) void = null,
889900};
890901
lib/std/os/bits/netbsd.zig+12-3
......@@ -716,13 +716,18 @@ pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
716716
717717/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
718718pub const Sigaction = extern struct {
719 pub const sigaction_fn = fn (i32, *siginfo_t, ?*c_void) callconv(.C) void;
719 pub const handler_fn = fn (c_int) callconv(.C) void;
720 pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void;
721
720722 /// signal handler
721 sigaction: ?sigaction_fn,
723 handler: extern union {
724 handler: ?handler_fn,
725 sigaction: ?sigaction_fn,
726 },
722727 /// signal mask to apply
723728 mask: sigset_t,
724729 /// signal options
725 flags: u32,
730 flags: c_uint,
726731};
727732
728733pub const sigval_t = extern union {
......@@ -800,6 +805,10 @@ pub const sigset_t = extern struct {
800805 __bits: [_SIG_WORDS]u32,
801806};
802807
808pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
809pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
810pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
811
803812pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS };
804813
805814// XXX x86_64 specific
lib/std/os/bits/openbsd.zig+22-11
......@@ -750,16 +750,23 @@ const NSIG = 33;
750750pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
751751pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
752752pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
753pub const SIG_CATCH = @intToPtr(?Sigaction.sigaction_fn, 2);
754pub const SIG_HOLD = @intToPtr(?Sigaction.sigaction_fn, 3);
753755
754756/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
755757pub const Sigaction = extern struct {
756 pub const sigaction_fn = fn (c_int, *siginfo_t, ?*c_void) callconv(.C) void;
758 pub const handler_fn = fn (c_int) callconv(.C) void;
759 pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void;
760
757761 /// signal handler
758 sigaction: ?sigaction_fn,
762 handler: extern union {
763 handler: ?handler_fn,
764 sigaction: ?sigaction_fn,
765 },
759766 /// signal mask to apply
760767 mask: sigset_t,
761768 /// signal options
762 flags: c_int,
769 flags: c_uint,
763770};
764771
765772pub const sigval = extern union {
......@@ -767,12 +774,7 @@ pub const sigval = extern union {
767774 ptr: ?*c_void,
768775};
769776
770pub const siginfo_t = extern union {
771 pad: [128]u8,
772 info: _ksiginfo,
773};
774
775pub const _ksiginfo = extern struct {
777pub const siginfo_t = extern struct {
776778 signo: c_int,
777779 code: c_int,
778780 errno: c_int,
......@@ -789,11 +791,20 @@ pub const _ksiginfo = extern struct {
789791 addr: ?*c_void,
790792 trapno: c_int,
791793 },
792 } align(@sizeOf(usize)),
794 __pad: [128 - 3 * @sizeOf(c_int)]u8,
795 },
793796};
794797
798comptime {
799 if (@sizeOf(usize) == 4)
800 std.debug.assert(@sizeOf(siginfo_t) == 128)
801 else
802 // Take into account the padding between errno and data fields.
803 std.debug.assert(@sizeOf(siginfo_t) == 136);
804}
805
795806pub const sigset_t = c_uint;
796pub const empty_sigset = sigset_t(0);
807pub const empty_sigset: sigset_t = 0;
797808
798809pub const EPERM = 1; // Operation not permitted
799810pub const ENOENT = 2; // No such file or directory
lib/std/os/linux.zig+27-20
......@@ -857,35 +857,42 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*
857857 return syscall4(.rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
858858}
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 {
861861 assert(sig >= 1);
862862 assert(sig != SIGKILL);
863863 assert(sig != SIGSTOP);
864864
865 const restorer_fn = if ((act.flags & SA_SIGINFO) != 0) restore_rt else restore;
866 var ksa = k_sigaction{
867 .sigaction = act.sigaction,
868 .flags = act.flags | SA_RESTORER,
869 .mask = undefined,
870 .restorer = @ptrCast(fn () callconv(.C) void, restorer_fn),
871 };
872 var ksa_old: k_sigaction = undefined;
873 const ksa_mask_size = @sizeOf(@TypeOf(ksa_old.mask));
874 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), ksa_mask_size);
865 var ksa: k_sigaction = undefined;
866 var oldksa: k_sigaction = undefined;
867 const mask_size = @sizeOf(@TypeOf(ksa.mask));
868
869 if (act) |new| {
870 const restorer_fn = if ((new.flags & SA_SIGINFO) != 0) restore_rt else restore;
871 ksa = k_sigaction{
872 .handler = new.handler.handler,
873 .flags = new.flags | SA_RESTORER,
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
875883 const result = switch (builtin.arch) {
876884 // 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),
878 else => syscall4(.rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), ksa_mask_size),
885 .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @ptrToInt(ksa.restorer), mask_size),
886 else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size),
879887 };
880 const err = getErrno(result);
881 if (err != 0) {
882 return result;
883 }
888 if (getErrno(result) != 0) return result;
889
884890 if (oact) |old| {
885 old.sigaction = ksa_old.sigaction;
886 old.flags = @truncate(u32, ksa_old.flags);
887 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), ksa_mask_size);
891 old.handler.handler = oldksa.handler;
892 old.flags = @truncate(c_uint, oldksa.flags);
893 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &oldksa.mask), mask_size);
888894 }
895
889896 return 0;
890897}
891898
lib/std/os/test.zig+38
......@@ -646,3 +646,41 @@ test "shutdown socket" {
646646 };
647647 os.closeSocket(sock);
648648}
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 // https://github.com/ziglang/zig/issues/7427
657 if (builtin.os.tag == .linux and builtin.arch == .i386)
658 return error.SkipZigTest;
659
660 const S = struct {
661 fn handler(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void {
662 // Check that we received the correct signal.
663 if (sig == os.SIGUSR1 and sig == info.signo)
664 signal_test_failed = false;
665 }
666 };
667
668 var sa = os.Sigaction{
669 .handler = .{ .sigaction = S.handler },
670 .mask = os.empty_sigset,
671 .flags = os.SA_SIGINFO | os.SA_RESETHAND,
672 };
673 var old_sa: os.Sigaction = undefined;
674 // Install the new signal handler.
675 os.sigaction(os.SIGUSR1, &sa, null);
676 // Check that we can read it back correctly.
677 os.sigaction(os.SIGUSR1, null, &old_sa);
678 testing.expectEqual(S.handler, old_sa.handler.sigaction.?);
679 testing.expect((old_sa.flags & os.SA_SIGINFO) != 0);
680 // Invoke the handler.
681 try os.raise(os.SIGUSR1);
682 testing.expect(signal_test_failed == false);
683 // Check if the handler has been correctly reset to SIG_DFL
684 os.sigaction(os.SIGUSR1, null, &old_sa);
685 testing.expectEqual(os.SIG_DFL, old_sa.handler.sigaction);
686}