summaryrefslogtreecommitdiff
path: root/test/sys/test_signal.rs
blob: 721cb9c9481a85633ed540247cf79b064d600e55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#[cfg(not(target_os = "redox"))]
use nix::errno::Errno;
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]
#[cfg(not(target_os = "fuchsia"))]
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();

    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();

    // 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!(
        !old_signal_set.contains(SIGNAL),
        "the {SIGNAL:?} signal is already blocked, please change to a \
             different one"
    );

    // 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!(
        old_signal_set.contains(SIGNAL),
        "expected the {SIGNAL:?} to be blocked"
    );

    // 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 "C" 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 "C" 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();

    let action_handler = SigHandler::SigAction(test_sigaction_action);
    assert_eq!(
        unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(),
        Errno::ENOTSUP
    );
}

#[test]
fn test_signal() {
    let _m = crate::SIGNAL_MTX.lock();

    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));

    #[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
    assert_eq!(
        unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
        handler
    );

    // System V based OSes (e.g. illumos and Solaris) always resets the
    // disposition to SIG_DFL prior to calling the signal handler
    #[cfg(any(target_os = "illumos", target_os = "solaris"))]
    assert_eq!(
        unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
        SigHandler::SigDfl
    );

    // Restore default signal handler
    unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
}