| ... | @@ -859,12 +859,64 @@ test "shutdown socket" { | ... | @@ -859,12 +859,64 @@ test "shutdown socket" { |
| 859 | std.net.Stream.close(.{ .handle = sock }); | 859 | std.net.Stream.close(.{ .handle = sock }); |
| 860 | } | 860 | } |
| 861 | | 861 | |
| 862 | test "sigaction" { | 862 | test "sigset empty/full" { |
| | 863 | if (native_os == .wasi or native_os == .windows) |
| | 864 | return error.SkipZigTest; |
| | 865 | |
| | 866 | var set: posix.sigset_t = undefined; |
| | 867 | |
| | 868 | posix.sigemptyset(&set); |
| | 869 | for (1..posix.NSIG) |i| { |
| | 870 | try expectEqual(false, posix.sigismember(&set, @truncate(i))); |
| | 871 | } |
| | 872 | |
| | 873 | // The C library can reserve some (unnamed) signals, so can't check the full |
| | 874 | // NSIG set is defined, but just test a couple: |
| | 875 | posix.sigfillset(&set); |
| | 876 | try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.USR1))); |
| | 877 | try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT))); |
| | 878 | } |
| | 879 | |
| | 880 | // Some signals (32 - 34 on glibc/musl) are not allowed to be added to a |
| | 881 | // sigset by the C library, so avoid testing them. |
| | 882 | fn reserved_signo(i: usize) bool { |
| | 883 | return builtin.link_libc and (i >= 32 and i <= 34); |
| | 884 | } |
| | 885 | |
| | 886 | test "sigset add/del" { |
| 863 | if (native_os == .wasi or native_os == .windows) | 887 | if (native_os == .wasi or native_os == .windows) |
| 864 | return error.SkipZigTest; | 888 | return error.SkipZigTest; |
| 865 | | 889 | |
| 866 | // https://github.com/ziglang/zig/issues/7427 | 890 | var sigset = posix.empty_sigset; |
| 867 | if (native_os == .linux and builtin.target.cpu.arch == .x86) | 891 | |
| | 892 | // See that none are set, then set each one, see that they're all set, then |
| | 893 | // remove them all, and then see that none are set. |
| | 894 | for (1..posix.NSIG) |i| { |
| | 895 | try expectEqual(false, posix.sigismember(&sigset, @truncate(i))); |
| | 896 | } |
| | 897 | for (1..posix.NSIG) |i| { |
| | 898 | if (!reserved_signo(i)) { |
| | 899 | posix.sigaddset(&sigset, @truncate(i)); |
| | 900 | } |
| | 901 | } |
| | 902 | for (1..posix.NSIG) |i| { |
| | 903 | if (!reserved_signo(i)) { |
| | 904 | try expectEqual(true, posix.sigismember(&sigset, @truncate(i))); |
| | 905 | } |
| | 906 | try expectEqual(false, posix.sigismember(&posix.empty_sigset, @truncate(i))); |
| | 907 | } |
| | 908 | for (1..posix.NSIG) |i| { |
| | 909 | if (!reserved_signo(i)) { |
| | 910 | posix.sigdelset(&sigset, @truncate(i)); |
| | 911 | } |
| | 912 | } |
| | 913 | for (1..posix.NSIG) |i| { |
| | 914 | try expectEqual(false, posix.sigismember(&sigset, @truncate(i))); |
| | 915 | } |
| | 916 | } |
| | 917 | |
| | 918 | test "sigaction" { |
| | 919 | if (native_os == .wasi or native_os == .windows) |
| 868 | return error.SkipZigTest; | 920 | return error.SkipZigTest; |
| 869 | | 921 | |
| 870 | // https://github.com/ziglang/zig/issues/15381 | 922 | // https://github.com/ziglang/zig/issues/15381 |
| ... | @@ -872,21 +924,20 @@ test "sigaction" { | ... | @@ -872,21 +924,20 @@ test "sigaction" { |
| 872 | return error.SkipZigTest; | 924 | return error.SkipZigTest; |
| 873 | } | 925 | } |
| 874 | | 926 | |
| | 927 | const test_signo = posix.SIG.USR1; |
| | 928 | |
| 875 | const S = struct { | 929 | const S = struct { |
| 876 | var handler_called_count: u32 = 0; | 930 | var handler_called_count: u32 = 0; |
| 877 | | 931 | |
| 878 | fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { | 932 | fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { |
| 879 | _ = ctx_ptr; | 933 | _ = ctx_ptr; |
| 880 | // Check that we received the correct signal. | 934 | // Check that we received the correct signal. |
| 881 | switch (native_os) { | 935 | const info_sig = switch (native_os) { |
| 882 | .netbsd => { | 936 | .netbsd => info.info.signo, |
| 883 | if (sig == posix.SIG.USR1 and sig == info.info.signo) | 937 | else => info.signo, |
| 884 | handler_called_count += 1; | 938 | }; |
| 885 | }, | 939 | if (sig == test_signo and sig == info_sig) { |
| 886 | else => { | 940 | handler_called_count += 1; |
| 887 | if (sig == posix.SIG.USR1 and sig == info.signo) | | |
| 888 | handler_called_count += 1; | | |
| 889 | }, | | |
| 890 | } | 941 | } |
| 891 | } | 942 | } |
| 892 | }; | 943 | }; |
| ... | @@ -899,39 +950,109 @@ test "sigaction" { | ... | @@ -899,39 +950,109 @@ test "sigaction" { |
| 899 | var old_sa: posix.Sigaction = undefined; | 950 | var old_sa: posix.Sigaction = undefined; |
| 900 | | 951 | |
| 901 | // Install the new signal handler. | 952 | // Install the new signal handler. |
| 902 | posix.sigaction(posix.SIG.USR1, &sa, null); | 953 | posix.sigaction(test_signo, &sa, null); |
| 903 | | 954 | |
| 904 | // Check that we can read it back correctly. | 955 | // Check that we can read it back correctly. |
| 905 | posix.sigaction(posix.SIG.USR1, null, &old_sa); | 956 | posix.sigaction(test_signo, null, &old_sa); |
| 906 | try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?); | 957 | try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?); |
| 907 | try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0); | 958 | try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0); |
| 908 | | 959 | |
| 909 | // Invoke the handler. | 960 | // Invoke the handler. |
| 910 | try posix.raise(posix.SIG.USR1); | 961 | try posix.raise(test_signo); |
| 911 | try testing.expect(S.handler_called_count == 1); | 962 | try testing.expectEqual(1, S.handler_called_count); |
| 912 | | 963 | |
| 913 | // Check if passing RESETHAND correctly reset the handler to SIG_DFL | 964 | // Check if passing RESETHAND correctly reset the handler to SIG_DFL |
| 914 | posix.sigaction(posix.SIG.USR1, null, &old_sa); | 965 | posix.sigaction(test_signo, null, &old_sa); |
| 915 | try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler); | 966 | try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler); |
| 916 | | 967 | |
| 917 | // Reinstall the signal w/o RESETHAND and re-raise | 968 | // Reinstall the signal w/o RESETHAND and re-raise |
| 918 | sa.flags = posix.SA.SIGINFO; | 969 | sa.flags = posix.SA.SIGINFO; |
| 919 | posix.sigaction(posix.SIG.USR1, &sa, null); | 970 | posix.sigaction(test_signo, &sa, null); |
| 920 | try posix.raise(posix.SIG.USR1); | 971 | try posix.raise(test_signo); |
| 921 | try testing.expect(S.handler_called_count == 2); | 972 | try testing.expectEqual(2, S.handler_called_count); |
| 922 | | 973 | |
| 923 | // Now set the signal to ignored | 974 | // Now set the signal to ignored |
| 924 | sa.handler = .{ .handler = posix.SIG.IGN }; | 975 | sa.handler = .{ .handler = posix.SIG.IGN }; |
| 925 | sa.flags = 0; | 976 | sa.flags = 0; |
| 926 | posix.sigaction(posix.SIG.USR1, &sa, null); | 977 | posix.sigaction(test_signo, &sa, null); |
| 927 | | 978 | |
| 928 | // Re-raise to ensure handler is actually ignored | 979 | // Re-raise to ensure handler is actually ignored |
| 929 | try posix.raise(posix.SIG.USR1); | 980 | try posix.raise(test_signo); |
| 930 | try testing.expect(S.handler_called_count == 2); | 981 | try testing.expectEqual(2, S.handler_called_count); |
| 931 | | 982 | |
| 932 | // Ensure that ignored state is returned when querying | 983 | // Ensure that ignored state is returned when querying |
| 933 | posix.sigaction(posix.SIG.USR1, null, &old_sa); | 984 | posix.sigaction(test_signo, null, &old_sa); |
| 934 | try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler.?); | 985 | try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler); |
| | 986 | } |
| | 987 | |
| | 988 | test "sigset_t bits" { |
| | 989 | if (native_os == .wasi or native_os == .windows) |
| | 990 | return error.SkipZigTest; |
| | 991 | |
| | 992 | const S = struct { |
| | 993 | var expected_sig: i32 = undefined; |
| | 994 | var handler_called_count: u32 = 0; |
| | 995 | |
| | 996 | fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void { |
| | 997 | _ = ctx_ptr; |
| | 998 | |
| | 999 | const info_sig = switch (native_os) { |
| | 1000 | .netbsd => info.info.signo, |
| | 1001 | else => info.signo, |
| | 1002 | }; |
| | 1003 | if (sig == expected_sig and sig == info_sig) { |
| | 1004 | handler_called_count += 1; |
| | 1005 | } |
| | 1006 | } |
| | 1007 | }; |
| | 1008 | |
| | 1009 | const self_pid = posix.system.getpid(); |
| | 1010 | |
| | 1011 | // To check that sigset_t mapping matches kernel (think u32/u64 |
| | 1012 | // mismatches on big-endian), try sending a blocked signal to make |
| | 1013 | // sure the mask matches the signal. |
| | 1014 | inline for ([_]usize{ posix.SIG.INT, posix.SIG.USR1, 62, 94, 126 }) |test_signo| { |
| | 1015 | if (test_signo >= posix.NSIG) continue; |
| | 1016 | |
| | 1017 | S.expected_sig = test_signo; |
| | 1018 | S.handler_called_count = 0; |
| | 1019 | |
| | 1020 | var sa: posix.Sigaction = .{ |
| | 1021 | .handler = .{ .sigaction = &S.handler }, |
| | 1022 | .mask = posix.empty_sigset, |
| | 1023 | .flags = posix.SA.SIGINFO | posix.SA.RESETHAND, |
| | 1024 | }; |
| | 1025 | var old_sa: posix.Sigaction = undefined; |
| | 1026 | |
| | 1027 | // Install the new signal handler. |
| | 1028 | posix.sigaction(test_signo, &sa, &old_sa); |
| | 1029 | |
| | 1030 | // block the signal and see that its delayed until unblocked |
| | 1031 | var block_one = posix.empty_sigset; |
| | 1032 | _ = posix.sigaddset(&block_one, test_signo); |
| | 1033 | posix.sigprocmask(posix.SIG.BLOCK, &block_one, null); |
| | 1034 | |
| | 1035 | // qemu maps target signals to host signals 1-to-1, so targets |
| | 1036 | // with more signals than the host will fail to send the signal. |
| | 1037 | const rc = posix.system.kill(self_pid, test_signo); |
| | 1038 | switch (posix.errno(rc)) { |
| | 1039 | .SUCCESS => { |
| | 1040 | // See that the signal is blocked, then unblocked |
| | 1041 | try testing.expectEqual(0, S.handler_called_count); |
| | 1042 | posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null); |
| | 1043 | try testing.expectEqual(1, S.handler_called_count); |
| | 1044 | }, |
| | 1045 | .INVAL => { |
| | 1046 | // Signal won't get delviered. Just clean up. |
| | 1047 | posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null); |
| | 1048 | try testing.expectEqual(0, S.handler_called_count); |
| | 1049 | }, |
| | 1050 | else => |errno| return posix.unexpectedErrno(errno), |
| | 1051 | } |
| | 1052 | |
| | 1053 | // Restore original handler |
| | 1054 | posix.sigaction(test_signo, &old_sa, null); |
| | 1055 | } |
| 935 | } | 1056 | } |
| 936 | | 1057 | |
| 937 | test "dup & dup2" { | 1058 | test "dup & dup2" { |