| 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 | 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 | 706 | test "dup & dup2" { |
| 854 | 707 | switch (native_os) { |
| 855 | 708 | .linux, .solaris, .illumos => {}, |
test/standalone/posix/sigaction.zig+153-1| ... | ... | @@ -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 | } |