| author | |
| committer | |
| log | bd4617033e09979398e65907a1d9c7f1b6e1d124 |
| tree | 9702481c64dfe4c79f8fa628b234664d28fef481 |
| parent | ca09629beeb899c418b16e5c180daf4d3f5ba3f9 |
Fixes #243802 files changed, 153 insertions(+), 148 deletions(-)
lib/std/posix/test.zig-147| ... | @@ -703,153 +703,6 @@ test "sigset add/del" { | ... | @@ -703,153 +703,6 @@ test "sigset add/del" { |
| 703 | } | 703 | } |
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | test "sigaction" { | ||
| 707 | if (native_os == .wasi or native_os == .windows) | ||
| 708 | return error.SkipZigTest; | ||
| 709 | |||
| 710 | // https://github.com/ziglang/zig/issues/15381 | ||
| 711 | if (native_os == .macos and builtin.target.cpu.arch == .x86_64) { | ||
| 712 | return error.SkipZigTest; | ||
| 713 | } | ||
| 714 | |||
| 715 | const test_signo = posix.SIG.URG; // URG only because it is ignored by default in debuggers | ||
| 716 | |||
| 717 | const S = struct { | ||
| 718 | var handler_called_count: u32 = 0; | ||
| 719 | |||
| 720 | fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { | ||
| 721 | _ = ctx_ptr; | ||
| 722 | // Check that we received the correct signal. | ||
| 723 | const info_sig = switch (native_os) { | ||
| 724 | .netbsd => info.info.signo, | ||
| 725 | else => info.signo, | ||
| 726 | }; | ||
| 727 | if (sig == test_signo and sig == info_sig) { | ||
| 728 | handler_called_count += 1; | ||
| 729 | } | ||
| 730 | } | ||
| 731 | }; | ||
| 732 | |||
| 733 | var sa: posix.Sigaction = .{ | ||
| 734 | .handler = .{ .sigaction = &S.handler }, | ||
| 735 | .mask = posix.sigemptyset(), | ||
| 736 | .flags = posix.SA.SIGINFO | posix.SA.RESETHAND, | ||
| 737 | }; | ||
| 738 | |||
| 739 | var old_sa: posix.Sigaction = undefined; | ||
| 740 | |||
| 741 | // Install the new signal handler. | ||
| 742 | posix.sigaction(test_signo, &sa, null); | ||
| 743 | |||
| 744 | // Check that we can read it back correctly. | ||
| 745 | posix.sigaction(test_signo, null, &old_sa); | ||
| 746 | try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?); | ||
| 747 | try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0); | ||
| 748 | |||
| 749 | // Invoke the handler. | ||
| 750 | try posix.raise(test_signo); | ||
| 751 | try testing.expectEqual(1, S.handler_called_count); | ||
| 752 | |||
| 753 | // Check if passing RESETHAND correctly reset the handler to SIG_DFL | ||
| 754 | posix.sigaction(test_signo, null, &old_sa); | ||
| 755 | try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler); | ||
| 756 | |||
| 757 | // Reinstall the signal w/o RESETHAND and re-raise | ||
| 758 | sa.flags = posix.SA.SIGINFO; | ||
| 759 | posix.sigaction(test_signo, &sa, null); | ||
| 760 | try posix.raise(test_signo); | ||
| 761 | try testing.expectEqual(2, S.handler_called_count); | ||
| 762 | |||
| 763 | // Now set the signal to ignored | ||
| 764 | sa.handler = .{ .handler = posix.SIG.IGN }; | ||
| 765 | sa.flags = 0; | ||
| 766 | posix.sigaction(test_signo, &sa, null); | ||
| 767 | |||
| 768 | // Re-raise to ensure handler is actually ignored | ||
| 769 | try posix.raise(test_signo); | ||
| 770 | try testing.expectEqual(2, S.handler_called_count); | ||
| 771 | |||
| 772 | // Ensure that ignored state is returned when querying | ||
| 773 | posix.sigaction(test_signo, null, &old_sa); | ||
| 774 | try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler); | ||
| 775 | } | ||
| 776 | |||
| 777 | test "sigset_t bits" { | ||
| 778 | if (native_os == .wasi or native_os == .windows) | ||
| 779 | return error.SkipZigTest; | ||
| 780 | |||
| 781 | const NO_SIG: i32 = 0; | ||
| 782 | |||
| 783 | const S = struct { | ||
| 784 | var expected_sig: i32 = undefined; | ||
| 785 | var seen_sig: i32 = NO_SIG; | ||
| 786 | |||
| 787 | fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { | ||
| 788 | _ = ctx_ptr; | ||
| 789 | |||
| 790 | const info_sig = switch (native_os) { | ||
| 791 | .netbsd => info.info.signo, | ||
| 792 | else => info.signo, | ||
| 793 | }; | ||
| 794 | if (seen_sig == NO_SIG and sig == expected_sig and sig == info_sig) { | ||
| 795 | seen_sig = sig; | ||
| 796 | } | ||
| 797 | } | ||
| 798 | }; | ||
| 799 | |||
| 800 | // Assume this is a single-threaded process where the current thread has the | ||
| 801 | // 'pid' thread id. (The sigprocmask calls are thread-private state.) | ||
| 802 | const self_tid = posix.system.getpid(); | ||
| 803 | |||
| 804 | // To check that sigset_t mapping matches kernel (think u32/u64 mismatches on | ||
| 805 | // big-endian), try sending a blocked signal to make sure the mask matches the | ||
| 806 | // signal. (Send URG and CHLD because they're ignored by default in the | ||
| 807 | // debugger, vs. USR1 or other named signals) | ||
| 808 | inline for ([_]i32{ posix.SIG.URG, posix.SIG.CHLD, 62, 94, 126 }) |test_signo| { | ||
| 809 | if (test_signo >= posix.NSIG) continue; | ||
| 810 | |||
| 811 | S.expected_sig = test_signo; | ||
| 812 | S.seen_sig = NO_SIG; | ||
| 813 | |||
| 814 | const sa: posix.Sigaction = .{ | ||
| 815 | .handler = .{ .sigaction = &S.handler }, | ||
| 816 | .mask = posix.sigemptyset(), | ||
| 817 | .flags = posix.SA.SIGINFO | posix.SA.RESETHAND, | ||
| 818 | }; | ||
| 819 | |||
| 820 | var old_sa: posix.Sigaction = undefined; | ||
| 821 | |||
| 822 | // Install the new signal handler. | ||
| 823 | posix.sigaction(test_signo, &sa, &old_sa); | ||
| 824 | |||
| 825 | // block the signal and see that its delayed until unblocked | ||
| 826 | var block_one: posix.sigset_t = posix.sigemptyset(); | ||
| 827 | posix.sigaddset(&block_one, test_signo); | ||
| 828 | posix.sigprocmask(posix.SIG.BLOCK, &block_one, null); | ||
| 829 | |||
| 830 | // qemu maps target signals to host signals 1-to-1, so targets | ||
| 831 | // with more signals than the host will fail to send the signal. | ||
| 832 | const rc = posix.system.kill(self_tid, test_signo); | ||
| 833 | switch (posix.errno(rc)) { | ||
| 834 | .SUCCESS => { | ||
| 835 | // See that the signal is blocked, then unblocked | ||
| 836 | try testing.expectEqual(NO_SIG, S.seen_sig); | ||
| 837 | posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null); | ||
| 838 | try testing.expectEqual(test_signo, S.seen_sig); | ||
| 839 | }, | ||
| 840 | .INVAL => { | ||
| 841 | // Signal won't get delviered. Just clean up. | ||
| 842 | posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null); | ||
| 843 | try testing.expectEqual(NO_SIG, S.seen_sig); | ||
| 844 | }, | ||
| 845 | else => |errno| return posix.unexpectedErrno(errno), | ||
| 846 | } | ||
| 847 | |||
| 848 | // Restore original handler | ||
| 849 | posix.sigaction(test_signo, &old_sa, null); | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | test "dup & dup2" { | 706 | test "dup & dup2" { |
| 854 | switch (native_os) { | 707 | switch (native_os) { |
| 855 | .linux, .solaris, .illumos => {}, | 708 | .linux, .solaris, .illumos => {}, |
test/standalone/posix/sigaction.zig+153-1| ... | @@ -1 +1,153 @@ | ... | @@ -1 +1,153 @@ |
| 1 | pub fn main() !void {} | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | const native_os = builtin.target.os.tag; | ||
| 5 | |||
| 6 | pub fn main() !void { | ||
| 7 | if (native_os == .wasi or native_os == .windows) { | ||
| 8 | return; // no sigaction | ||
| 9 | } | ||
| 10 | |||
| 11 | try test_sigaction(); | ||
| 12 | try test_sigset_bits(); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn test_sigaction() !void { | ||
| 16 | if (native_os == .macos and builtin.target.cpu.arch == .x86_64) { | ||
| 17 | return; // https://github.com/ziglang/zig/issues/15381 | ||
| 18 | } | ||
| 19 | |||
| 20 | const test_signo = std.posix.SIG.URG; // URG only because it is ignored by default in debuggers | ||
| 21 | |||
| 22 | const S = struct { | ||
| 23 | var handler_called_count: u32 = 0; | ||
| 24 | |||
| 25 | fn handler(sig: i32, info: *const std.posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { | ||
| 26 | _ = ctx_ptr; | ||
| 27 | // Check that we received the correct signal. | ||
| 28 | const info_sig = switch (native_os) { | ||
| 29 | .netbsd => info.info.signo, | ||
| 30 | else => info.signo, | ||
| 31 | }; | ||
| 32 | if (sig == test_signo and sig == info_sig) { | ||
| 33 | handler_called_count += 1; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | |||
| 38 | var sa: std.posix.Sigaction = .{ | ||
| 39 | .handler = .{ .sigaction = &S.handler }, | ||
| 40 | .mask = std.posix.sigemptyset(), | ||
| 41 | .flags = std.posix.SA.SIGINFO | std.posix.SA.RESETHAND, | ||
| 42 | }; | ||
| 43 | |||
| 44 | var old_sa: std.posix.Sigaction = undefined; | ||
| 45 | |||
| 46 | // Install the new signal handler. | ||
| 47 | std.posix.sigaction(test_signo, &sa, null); | ||
| 48 | |||
| 49 | // Check that we can read it back correctly. | ||
| 50 | std.posix.sigaction(test_signo, null, &old_sa); | ||
| 51 | try std.testing.expectEqual(&S.handler, old_sa.handler.sigaction.?); | ||
| 52 | try std.testing.expect((old_sa.flags & std.posix.SA.SIGINFO) != 0); | ||
| 53 | |||
| 54 | // Invoke the handler. | ||
| 55 | try std.posix.raise(test_signo); | ||
| 56 | try std.testing.expectEqual(1, S.handler_called_count); | ||
| 57 | |||
| 58 | // Check if passing RESETHAND correctly reset the handler to SIG_DFL | ||
| 59 | std.posix.sigaction(test_signo, null, &old_sa); | ||
| 60 | try std.testing.expectEqual(std.posix.SIG.DFL, old_sa.handler.handler); | ||
| 61 | |||
| 62 | // Reinstall the signal w/o RESETHAND and re-raise | ||
| 63 | sa.flags = std.posix.SA.SIGINFO; | ||
| 64 | std.posix.sigaction(test_signo, &sa, null); | ||
| 65 | try std.posix.raise(test_signo); | ||
| 66 | try std.testing.expectEqual(2, S.handler_called_count); | ||
| 67 | |||
| 68 | // Now set the signal to ignored | ||
| 69 | sa.handler = .{ .handler = std.posix.SIG.IGN }; | ||
| 70 | sa.flags = 0; | ||
| 71 | std.posix.sigaction(test_signo, &sa, null); | ||
| 72 | |||
| 73 | // Re-raise to ensure handler is actually ignored | ||
| 74 | try std.posix.raise(test_signo); | ||
| 75 | try std.testing.expectEqual(2, S.handler_called_count); | ||
| 76 | |||
| 77 | // Ensure that ignored state is returned when querying | ||
| 78 | std.posix.sigaction(test_signo, null, &old_sa); | ||
| 79 | try std.testing.expectEqual(std.posix.SIG.IGN, old_sa.handler.handler); | ||
| 80 | } | ||
| 81 | |||
| 82 | fn test_sigset_bits() !void { | ||
| 83 | const NO_SIG: i32 = 0; | ||
| 84 | |||
| 85 | const S = struct { | ||
| 86 | var expected_sig: i32 = undefined; | ||
| 87 | var seen_sig: i32 = NO_SIG; | ||
| 88 | |||
| 89 | fn handler(sig: i32, info: *const std.posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { | ||
| 90 | _ = ctx_ptr; | ||
| 91 | |||
| 92 | const info_sig = switch (native_os) { | ||
| 93 | .netbsd => info.info.signo, | ||
| 94 | else => info.signo, | ||
| 95 | }; | ||
| 96 | if (seen_sig == NO_SIG and sig == expected_sig and sig == info_sig) { | ||
| 97 | seen_sig = sig; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | }; | ||
| 101 | |||
| 102 | // Assume this is a single-threaded process where the current thread has the | ||
| 103 | // 'pid' thread id. (The sigprocmask calls are thread-private state.) | ||
| 104 | const self_tid = std.posix.system.getpid(); | ||
| 105 | |||
| 106 | // To check that sigset_t mapping matches kernel (think u32/u64 mismatches on | ||
| 107 | // big-endian), try sending a blocked signal to make sure the mask matches the | ||
| 108 | // signal. (Send URG and CHLD because they're ignored by default in the | ||
| 109 | // debugger, vs. USR1 or other named signals) | ||
| 110 | inline for ([_]i32{ std.posix.SIG.URG, std.posix.SIG.CHLD, 62, 94, 126 }) |test_signo| { | ||
| 111 | if (test_signo >= std.posix.NSIG) continue; | ||
| 112 | |||
| 113 | S.expected_sig = test_signo; | ||
| 114 | S.seen_sig = NO_SIG; | ||
| 115 | |||
| 116 | const sa: std.posix.Sigaction = .{ | ||
| 117 | .handler = .{ .sigaction = &S.handler }, | ||
| 118 | .mask = std.posix.sigemptyset(), | ||
| 119 | .flags = std.posix.SA.SIGINFO | std.posix.SA.RESETHAND, | ||
| 120 | }; | ||
| 121 | |||
| 122 | var old_sa: std.posix.Sigaction = undefined; | ||
| 123 | |||
| 124 | // Install the new signal handler. | ||
| 125 | std.posix.sigaction(test_signo, &sa, &old_sa); | ||
| 126 | |||
| 127 | // block the signal and see that its delayed until unblocked | ||
| 128 | var block_one: std.posix.sigset_t = std.posix.sigemptyset(); | ||
| 129 | std.posix.sigaddset(&block_one, test_signo); | ||
| 130 | std.posix.sigprocmask(std.posix.SIG.BLOCK, &block_one, null); | ||
| 131 | |||
| 132 | // qemu maps target signals to host signals 1-to-1, so targets | ||
| 133 | // with more signals than the host will fail to send the signal. | ||
| 134 | const rc = std.posix.system.kill(self_tid, test_signo); | ||
| 135 | switch (std.posix.errno(rc)) { | ||
| 136 | .SUCCESS => { | ||
| 137 | // See that the signal is blocked, then unblocked | ||
| 138 | try std.testing.expectEqual(NO_SIG, S.seen_sig); | ||
| 139 | std.posix.sigprocmask(std.posix.SIG.UNBLOCK, &block_one, null); | ||
| 140 | try std.testing.expectEqual(test_signo, S.seen_sig); | ||
| 141 | }, | ||
| 142 | .INVAL => { | ||
| 143 | // Signal won't get delviered. Just clean up. | ||
| 144 | std.posix.sigprocmask(std.posix.SIG.UNBLOCK, &block_one, null); | ||
| 145 | try std.testing.expectEqual(NO_SIG, S.seen_sig); | ||
| 146 | }, | ||
| 147 | else => |errno| return std.posix.unexpectedErrno(errno), | ||
| 148 | } | ||
| 149 | |||
| 150 | // Restore original handler | ||
| 151 | std.posix.sigaction(test_signo, &old_sa, null); | ||
| 152 | } | ||
| 153 | } |