1#[cfg(not(target_os = "redox"))]
2use nix::errno::Errno;
3use nix::sys::signal::*;
4use nix::unistd::*;
5use std::convert::TryFrom;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8#[test]
9fn 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"))]
15fn test_killpg_none() {
16    killpg(getpgrp(), None)
17        .expect("Should be able to send signal to my process group.");
18}
19
20#[test]
21fn 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]
37fn test_sigprocmask_noop() {
38    sigprocmask(SigmaskHow::SIG_BLOCK, None, None)
39        .expect("this should be an effective noop");
40}
41
42#[test]
43fn 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 is already blocked, please change to a \
58             different one",
59        SIGNAL
60    );
61
62    // Now block the signal.
63    let mut signal_set = SigSet::empty();
64    signal_set.add(SIGNAL);
65    sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None)
66        .expect("expect to be able to block signals");
67
68    // And test it again, to make sure the change was effective.
69    old_signal_set.clear();
70    sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
71        .expect("expect to be able to retrieve old signals");
72    assert!(
73        old_signal_set.contains(SIGNAL),
74        "expected the {:?} to be blocked",
75        SIGNAL
76    );
77
78    // Reset the signal.
79    sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None)
80        .expect("expect to be able to block signals");
81}
82
83lazy_static! {
84    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
85}
86
87extern "C" fn test_sigaction_handler(signal: libc::c_int) {
88    let signal = Signal::try_from(signal).unwrap();
89    SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
90}
91
92#[cfg(not(target_os = "redox"))]
93extern "C" fn test_sigaction_action(
94    _: libc::c_int,
95    _: *mut libc::siginfo_t,
96    _: *mut libc::c_void,
97) {
98}
99
100#[test]
101#[cfg(not(target_os = "redox"))]
102fn test_signal_sigaction() {
103    let _m = crate::SIGNAL_MTX.lock();
104
105    let action_handler = SigHandler::SigAction(test_sigaction_action);
106    assert_eq!(
107        unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(),
108        Errno::ENOTSUP
109    );
110}
111
112#[test]
113fn test_signal() {
114    let _m = crate::SIGNAL_MTX.lock();
115
116    unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
117    raise(Signal::SIGINT).unwrap();
118    assert_eq!(
119        unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
120        SigHandler::SigIgn
121    );
122
123    let handler = SigHandler::Handler(test_sigaction_handler);
124    assert_eq!(
125        unsafe { signal(Signal::SIGINT, handler) }.unwrap(),
126        SigHandler::SigDfl
127    );
128    raise(Signal::SIGINT).unwrap();
129    assert!(SIGNALED.load(Ordering::Relaxed));
130
131    #[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
132    assert_eq!(
133        unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
134        handler
135    );
136
137    // System V based OSes (e.g. illumos and Solaris) always resets the
138    // disposition to SIG_DFL prior to calling the signal handler
139    #[cfg(any(target_os = "illumos", target_os = "solaris"))]
140    assert_eq!(
141        unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
142        SigHandler::SigDfl
143    );
144
145    // Restore default signal handler
146    unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
147}
148