| use libc; |
| #[cfg(not(target_os = "redox"))] |
| use nix::Error; |
| use nix::sys::signal::*; |
| use nix::unistd::*; |
| use std::convert::TryFrom; |
| use std::sync::atomic::{AtomicBool, Ordering}; |
| |
| #[test] |
| fn test_kill_none() { |
| kill(getpid(), None).expect("Should be able to send signal to myself."); |
| } |
| |
| #[test] |
| fn test_killpg_none() { |
| killpg(getpgrp(), None) |
| .expect("Should be able to send signal to my process group."); |
| } |
| |
| #[test] |
| fn test_old_sigaction_flags() { |
| let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); |
| |
| extern "C" fn handler(_: ::libc::c_int) {} |
| let act = SigAction::new( |
| SigHandler::Handler(handler), |
| SaFlags::empty(), |
| SigSet::empty(), |
| ); |
| let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); |
| let _flags = oact.flags(); |
| let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); |
| let _flags = oact.flags(); |
| } |
| |
| #[test] |
| fn test_sigprocmask_noop() { |
| sigprocmask(SigmaskHow::SIG_BLOCK, None, None) |
| .expect("this should be an effective noop"); |
| } |
| |
| #[test] |
| fn test_sigprocmask() { |
| let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); |
| |
| // This needs to be a signal that rust doesn't use in the test harness. |
| const SIGNAL: Signal = Signal::SIGCHLD; |
| |
| let mut old_signal_set = SigSet::empty(); |
| sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) |
| .expect("expect to be able to retrieve old signals"); |
| |
| // Make sure the old set doesn't contain the signal, otherwise the following |
| // test don't make sense. |
| assert_eq!(old_signal_set.contains(SIGNAL), false, |
| "the {:?} signal is already blocked, please change to a \ |
| different one", SIGNAL); |
| |
| // Now block the signal. |
| let mut signal_set = SigSet::empty(); |
| signal_set.add(SIGNAL); |
| sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None) |
| .expect("expect to be able to block signals"); |
| |
| // And test it again, to make sure the change was effective. |
| old_signal_set.clear(); |
| sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) |
| .expect("expect to be able to retrieve old signals"); |
| assert_eq!(old_signal_set.contains(SIGNAL), true, |
| "expected the {:?} to be blocked", SIGNAL); |
| |
| // Reset the signal. |
| sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) |
| .expect("expect to be able to block signals"); |
| } |
| |
| lazy_static! { |
| static ref SIGNALED: AtomicBool = AtomicBool::new(false); |
| } |
| |
| extern fn test_sigaction_handler(signal: libc::c_int) { |
| let signal = Signal::try_from(signal).unwrap(); |
| SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); |
| } |
| |
| #[cfg(not(target_os = "redox"))] |
| extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {} |
| |
| #[test] |
| #[cfg(not(target_os = "redox"))] |
| fn test_signal_sigaction() { |
| let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); |
| |
| let action_handler = SigHandler::SigAction(test_sigaction_action); |
| assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation); |
| } |
| |
| #[test] |
| fn test_signal() { |
| let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); |
| |
| unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); |
| raise(Signal::SIGINT).unwrap(); |
| assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn); |
| |
| let handler = SigHandler::Handler(test_sigaction_handler); |
| assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl); |
| raise(Signal::SIGINT).unwrap(); |
| assert!(SIGNALED.load(Ordering::Relaxed)); |
| assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler); |
| |
| // Restore default signal handler |
| unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); |
| } |