140 lines
4.0 KiB
Rust
140 lines
4.0 KiB
Rust
// These tests cannot run as a regular test because cargo would spawn a thread to run it,
|
|
// failing the signal masking. So we make our own, non-threaded harnessing
|
|
|
|
#[cfg(all(target_os = "linux", feature = "signals"))]
|
|
fn main() {
|
|
for test in self::test::TESTS {
|
|
test();
|
|
// reset the signal mask between tests
|
|
self::test::reset_mask();
|
|
}
|
|
}
|
|
|
|
#[cfg(not(all(target_os = "linux", feature = "signals")))]
|
|
fn main() {}
|
|
|
|
#[cfg(all(target_os = "linux", feature = "signals"))]
|
|
mod test {
|
|
extern crate calloop;
|
|
extern crate nix;
|
|
|
|
use std::time::Duration;
|
|
|
|
use self::calloop::signals::{Signal, Signals};
|
|
use self::calloop::{Dispatcher, EventLoop};
|
|
|
|
use self::nix::sys::signal::{kill, SigSet};
|
|
use self::nix::unistd::Pid;
|
|
|
|
pub const TESTS: &[fn()] = &[single_usr1, usr2_added_afterwards, usr2_signal_removed];
|
|
|
|
pub fn reset_mask() {
|
|
SigSet::empty().thread_set_mask().unwrap();
|
|
}
|
|
|
|
fn single_usr1() {
|
|
let mut event_loop = EventLoop::try_new().unwrap();
|
|
|
|
let mut signal_received = false;
|
|
|
|
let _signal_source = event_loop
|
|
.handle()
|
|
.insert_source(
|
|
Signals::new(&[Signal::SIGUSR1]).unwrap(),
|
|
move |evt, &mut (), rcv| {
|
|
assert!(evt.signal() == Signal::SIGUSR1);
|
|
*rcv = true;
|
|
},
|
|
)
|
|
.unwrap();
|
|
|
|
// send ourselves a SIGUSR1
|
|
kill(Pid::this(), Signal::SIGUSR1).unwrap();
|
|
|
|
event_loop
|
|
.dispatch(Some(Duration::from_millis(10)), &mut signal_received)
|
|
.unwrap();
|
|
|
|
assert!(signal_received);
|
|
}
|
|
|
|
fn usr2_added_afterwards() {
|
|
let mut event_loop = EventLoop::try_new().unwrap();
|
|
|
|
let mut signal_received = None;
|
|
let dispatcher = Dispatcher::new(
|
|
Signals::new(&[Signal::SIGUSR1]).unwrap(),
|
|
move |evt, &mut (), rcv| {
|
|
*rcv = Some(evt.signal());
|
|
},
|
|
);
|
|
|
|
let _signal_token = event_loop
|
|
.handle()
|
|
.register_dispatcher(dispatcher.clone())
|
|
.unwrap();
|
|
dispatcher
|
|
.as_source_mut()
|
|
.add_signals(&[Signal::SIGUSR2])
|
|
.unwrap();
|
|
|
|
// send ourselves a SIGUSR2
|
|
kill(Pid::this(), Signal::SIGUSR2).unwrap();
|
|
|
|
event_loop
|
|
.dispatch(Some(Duration::from_millis(10)), &mut signal_received)
|
|
.unwrap();
|
|
|
|
assert_eq!(signal_received, Some(Signal::SIGUSR2));
|
|
}
|
|
|
|
fn usr2_signal_removed() {
|
|
let mut event_loop = EventLoop::try_new().unwrap();
|
|
|
|
let mut signal_received = None;
|
|
let dispatcher = Dispatcher::new(
|
|
Signals::new(&[Signal::SIGUSR1, Signal::SIGUSR2]).unwrap(),
|
|
move |evt, &mut (), rcv| {
|
|
*rcv = Some(evt.signal());
|
|
},
|
|
);
|
|
|
|
let _signal_token = event_loop
|
|
.handle()
|
|
.register_dispatcher(dispatcher.clone())
|
|
.unwrap();
|
|
dispatcher
|
|
.as_source_mut()
|
|
.remove_signals(&[Signal::SIGUSR2])
|
|
.unwrap();
|
|
|
|
// block sigusr2 anyway, to not be killed by it
|
|
let mut set = SigSet::empty();
|
|
set.add(Signal::SIGUSR2);
|
|
set.thread_block().unwrap();
|
|
|
|
// send ourselves a SIGUSR2
|
|
kill(Pid::this(), Signal::SIGUSR2).unwrap();
|
|
|
|
event_loop
|
|
.dispatch(Some(Duration::from_millis(10)), &mut signal_received)
|
|
.unwrap();
|
|
|
|
// we should not have received anything, as we don't listen to SIGUSR2 any more
|
|
assert!(signal_received.is_none());
|
|
|
|
// swap the signals from [SIGUSR1] to [SIGUSR2]
|
|
dispatcher
|
|
.as_source_mut()
|
|
.set_signals(&[Signal::SIGUSR2])
|
|
.unwrap();
|
|
|
|
event_loop
|
|
.dispatch(Some(Duration::from_millis(10)), &mut signal_received)
|
|
.unwrap();
|
|
|
|
// we should get back the pending SIGUSR2 now
|
|
assert_eq!(signal_received, Some(Signal::SIGUSR2));
|
|
}
|
|
}
|