| 1 | #[cfg (not(target_os = "redox" ))] |
| 2 | use nix::errno::Errno; |
| 3 | use nix::sys::signal::*; |
| 4 | use nix::unistd::*; |
| 5 | use std::convert::TryFrom; |
| 6 | use std::sync::atomic::{AtomicBool, Ordering}; |
| 7 | |
| 8 | #[test] |
| 9 | fn test_kill_none() { |
| 10 | kill(getpid(), None).expect("Should be able to send signal to myself." ); |
| 11 | } |
| 12 | |
| 13 | #[test] |
| 14 | #[cfg (not(target_os = "fuchsia" ))] |
| 15 | fn test_killpg_none() { |
| 16 | killpg(getpgrp(), None) |
| 17 | .expect("Should be able to send signal to my process group." ); |
| 18 | } |
| 19 | |
| 20 | #[test] |
| 21 | fn test_old_sigaction_flags() { |
| 22 | let _m = crate::SIGNAL_MTX.lock(); |
| 23 | |
| 24 | extern "C" fn handler(_: ::libc::c_int) {} |
| 25 | let act = SigAction::new( |
| 26 | SigHandler::Handler(handler), |
| 27 | SaFlags::empty(), |
| 28 | SigSet::empty(), |
| 29 | ); |
| 30 | let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); |
| 31 | let _flags = oact.flags(); |
| 32 | let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); |
| 33 | let _flags = oact.flags(); |
| 34 | } |
| 35 | |
| 36 | #[test] |
| 37 | fn test_sigprocmask_noop() { |
| 38 | sigprocmask(SigmaskHow::SIG_BLOCK, None, None) |
| 39 | .expect("this should be an effective noop" ); |
| 40 | } |
| 41 | |
| 42 | #[test] |
| 43 | fn test_sigprocmask() { |
| 44 | let _m = crate::SIGNAL_MTX.lock(); |
| 45 | |
| 46 | // This needs to be a signal that rust doesn't use in the test harness. |
| 47 | const SIGNAL: Signal = Signal::SIGCHLD; |
| 48 | |
| 49 | let mut old_signal_set = SigSet::empty(); |
| 50 | sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) |
| 51 | .expect("expect to be able to retrieve old signals" ); |
| 52 | |
| 53 | // Make sure the old set doesn't contain the signal, otherwise the following |
| 54 | // test don't make sense. |
| 55 | assert!( |
| 56 | !old_signal_set.contains(SIGNAL), |
| 57 | "the {SIGNAL:?} signal is already blocked, please change to a \ |
| 58 | different one" |
| 59 | ); |
| 60 | |
| 61 | // Now block the signal. |
| 62 | let mut signal_set = SigSet::empty(); |
| 63 | signal_set.add(SIGNAL); |
| 64 | sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None) |
| 65 | .expect("expect to be able to block signals" ); |
| 66 | |
| 67 | // And test it again, to make sure the change was effective. |
| 68 | old_signal_set.clear(); |
| 69 | sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) |
| 70 | .expect("expect to be able to retrieve old signals" ); |
| 71 | assert!( |
| 72 | old_signal_set.contains(SIGNAL), |
| 73 | "expected the {SIGNAL:?} to be blocked" |
| 74 | ); |
| 75 | |
| 76 | // Reset the signal. |
| 77 | sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) |
| 78 | .expect("expect to be able to block signals" ); |
| 79 | } |
| 80 | |
| 81 | static SIGNALED: AtomicBool = AtomicBool::new(false); |
| 82 | |
| 83 | extern "C" fn test_sigaction_handler(signal: libc::c_int) { |
| 84 | let signal = Signal::try_from(signal).unwrap(); |
| 85 | SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); |
| 86 | } |
| 87 | |
| 88 | #[cfg (not(target_os = "redox" ))] |
| 89 | extern "C" fn test_sigaction_action( |
| 90 | _: libc::c_int, |
| 91 | _: *mut libc::siginfo_t, |
| 92 | _: *mut libc::c_void, |
| 93 | ) { |
| 94 | } |
| 95 | |
| 96 | #[test] |
| 97 | #[cfg (not(target_os = "redox" ))] |
| 98 | fn test_signal_sigaction() { |
| 99 | let _m = crate::SIGNAL_MTX.lock(); |
| 100 | |
| 101 | let action_handler = SigHandler::SigAction(test_sigaction_action); |
| 102 | assert_eq!( |
| 103 | unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), |
| 104 | Errno::ENOTSUP |
| 105 | ); |
| 106 | } |
| 107 | |
| 108 | #[test] |
| 109 | fn test_signal() { |
| 110 | let _m = crate::SIGNAL_MTX.lock(); |
| 111 | |
| 112 | unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); |
| 113 | raise(Signal::SIGINT).unwrap(); |
| 114 | assert_eq!( |
| 115 | unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), |
| 116 | SigHandler::SigIgn |
| 117 | ); |
| 118 | |
| 119 | let handler = SigHandler::Handler(test_sigaction_handler); |
| 120 | assert_eq!( |
| 121 | unsafe { signal(Signal::SIGINT, handler) }.unwrap(), |
| 122 | SigHandler::SigDfl |
| 123 | ); |
| 124 | raise(Signal::SIGINT).unwrap(); |
| 125 | assert!(SIGNALED.load(Ordering::Relaxed)); |
| 126 | |
| 127 | #[cfg (not(any(target_os = "illumos" , target_os = "solaris" )))] |
| 128 | assert_eq!( |
| 129 | unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), |
| 130 | handler |
| 131 | ); |
| 132 | |
| 133 | // System V based OSes (e.g. illumos and Solaris) always resets the |
| 134 | // disposition to SIG_DFL prior to calling the signal handler |
| 135 | #[cfg (any(target_os = "illumos" , target_os = "solaris" ))] |
| 136 | assert_eq!( |
| 137 | unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), |
| 138 | SigHandler::SigDfl |
| 139 | ); |
| 140 | |
| 141 | // Restore default signal handler |
| 142 | unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); |
| 143 | } |
| 144 | |