1 #![cfg(not(windows))]
2
3 extern crate signal_hook;
4
5 use std::collections::HashSet;
6 use std::sync::atomic::{AtomicBool, Ordering};
7 use std::sync::mpsc::{self, RecvTimeoutError};
8 use std::sync::Arc;
9 use std::thread::{self, JoinHandle};
10 use std::time::Duration;
11
12 use signal_hook::consts::{SIGUSR1, SIGUSR2};
13 use signal_hook::iterator::{Handle, Signals};
14 use signal_hook::low_level::raise;
15
16 use serial_test::serial;
17
send_sigusr1()18 fn send_sigusr1() {
19 raise(SIGUSR1).unwrap();
20 }
21
send_sigusr2()22 fn send_sigusr2() {
23 raise(SIGUSR2).unwrap();
24 }
25
setup_without_any_signals() -> (Signals, Handle)26 fn setup_without_any_signals() -> (Signals, Handle) {
27 let signals = Signals::new(&[]).unwrap();
28 let controller = signals.handle();
29 (signals, controller)
30 }
31
setup_for_sigusr2() -> (Signals, Handle)32 fn setup_for_sigusr2() -> (Signals, Handle) {
33 let signals = Signals::new(&[SIGUSR2]).unwrap();
34 let controller = signals.handle();
35 (signals, controller)
36 }
37
38 macro_rules! assert_signals {
39 ($actual:expr, $($expected:expr),+ $(,)?) => {
40 let actual = $actual.collect::<HashSet<libc::c_int>>();
41 let expected = vec!($($expected),+).into_iter().collect::<HashSet<libc::c_int>>();
42 assert_eq!(actual, expected);
43 };
44 }
45
46 macro_rules! assert_no_signals {
47 ($signals:expr) => {
48 assert_eq!($signals.next(), None);
49 };
50 }
51
52 #[test]
53 #[serial]
forever_terminates_when_closed()54 fn forever_terminates_when_closed() {
55 let (mut signals, controller) = setup_for_sigusr2();
56
57 // Detect early terminations.
58 let stopped = Arc::new(AtomicBool::new(false));
59
60 let stopped_bg = Arc::clone(&stopped);
61 let thread = thread::spawn(move || {
62 // Eat all the signals there are (might come from a concurrent test, in theory).
63 // Would wait forever, but it should be terminated by the close below.
64 for _sig in &mut signals {}
65
66 stopped_bg.store(true, Ordering::SeqCst);
67 });
68
69 // Wait a bit to see if the thread terminates by itself.
70 thread::sleep(Duration::from_millis(100));
71 assert!(!stopped.load(Ordering::SeqCst));
72
73 controller.close();
74
75 thread.join().unwrap();
76
77 assert!(stopped.load(Ordering::SeqCst));
78 }
79
80 // A reproducer for #16: if we had the mio-support enabled (which is enabled also by the
81 // tokio-support feature), blocking no longer works. The .wait() would return immediately (an empty
82 // iterator, possibly), .forever() would do a busy loop.
83 // flag)
84 #[test]
85 #[serial]
signals_block_wait()86 fn signals_block_wait() {
87 let mut signals = Signals::new(&[SIGUSR2]).unwrap();
88 let (s, r) = mpsc::channel();
89 let finish = Arc::new(AtomicBool::new(false));
90 let thread_id = thread::spawn({
91 let finish = Arc::clone(&finish);
92 move || {
93 // Technically, it may spuriously return early. But it shouldn't be doing it too much,
94 // so we just try to wait multiple times ‒ if they *all* return right away, it is
95 // broken.
96 for _ in 0..10 {
97 for _ in signals.wait() {
98 if finish.load(Ordering::SeqCst) {
99 // Asked to terminate at the end of the thread. Do so (but without
100 // signalling the receipt).
101 return;
102 } else {
103 panic!("Someone really did send us SIGUSR2, which breaks the test");
104 }
105 }
106 }
107 let _ = s.send(());
108 }
109 });
110
111 // A RAII guard to make sure we shut down the thread even if the test fails.
112 struct ThreadGuard {
113 thread: Option<JoinHandle<()>>,
114 finish: Arc<AtomicBool>,
115 }
116
117 impl ThreadGuard {
118 fn shutdown(&mut self) {
119 // Tell it to shut down
120 self.finish.store(true, Ordering::SeqCst);
121 // Wake it up
122 send_sigusr2();
123 // Wait for it to actually terminate.
124 if let Some(thread) = self.thread.take() {
125 thread.join().unwrap(); // Propagate panics
126 }
127 }
128 }
129
130 impl Drop for ThreadGuard {
131 fn drop(&mut self) {
132 self.shutdown(); // OK if done twice, won't have the thread any more.
133 }
134 }
135
136 let mut bg_thread = ThreadGuard {
137 thread: Some(thread_id),
138 finish,
139 };
140
141 let err = r
142 .recv_timeout(Duration::from_millis(100))
143 .expect_err("Wait didn't wait properly");
144 assert_eq!(err, RecvTimeoutError::Timeout);
145
146 bg_thread.shutdown();
147 }
148
149 #[test]
150 #[serial]
pending_doesnt_block()151 fn pending_doesnt_block() {
152 let (mut signals, _) = setup_for_sigusr2();
153
154 let mut recieved_signals = signals.pending();
155
156 assert_no_signals!(recieved_signals);
157 }
158
159 #[test]
160 #[serial]
wait_returns_recieved_signals()161 fn wait_returns_recieved_signals() {
162 let (mut signals, _) = setup_for_sigusr2();
163 send_sigusr2();
164
165 let recieved_signals = signals.wait();
166
167 assert_signals!(recieved_signals, SIGUSR2);
168 }
169
170 #[test]
171 #[serial]
forever_returns_recieved_signals()172 fn forever_returns_recieved_signals() {
173 let (mut signals, _) = setup_for_sigusr2();
174 send_sigusr2();
175
176 let signal = signals.forever().take(1);
177
178 assert_signals!(signal, SIGUSR2);
179 }
180
181 #[test]
182 #[serial]
wait_doesnt_block_when_closed()183 fn wait_doesnt_block_when_closed() {
184 let (mut signals, controller) = setup_for_sigusr2();
185 controller.close();
186
187 let mut recieved_signals = signals.wait();
188
189 assert_no_signals!(recieved_signals);
190 }
191
192 #[test]
193 #[serial]
wait_unblocks_when_closed()194 fn wait_unblocks_when_closed() {
195 let (mut signals, controller) = setup_without_any_signals();
196
197 let thread = thread::spawn(move || {
198 signals.wait();
199 });
200
201 controller.close();
202
203 thread.join().unwrap();
204 }
205
206 #[test]
207 #[serial]
forever_doesnt_block_when_closed()208 fn forever_doesnt_block_when_closed() {
209 let (mut signals, controller) = setup_for_sigusr2();
210 controller.close();
211
212 let mut signal = signals.forever();
213
214 assert_no_signals!(signal);
215 }
216
217 #[test]
218 #[serial]
add_signal_after_creation()219 fn add_signal_after_creation() {
220 let (mut signals, _) = setup_without_any_signals();
221 signals.add_signal(SIGUSR1).unwrap();
222
223 send_sigusr1();
224
225 assert_signals!(signals.pending(), SIGUSR1);
226 }
227
228 #[test]
229 #[serial]
delayed_signal_consumed()230 fn delayed_signal_consumed() {
231 let (mut signals, _) = setup_for_sigusr2();
232 signals.add_signal(SIGUSR1).unwrap();
233
234 send_sigusr1();
235 let mut recieved_signals = signals.wait();
236 send_sigusr2();
237
238 assert_signals!(recieved_signals, SIGUSR1, SIGUSR2);
239
240 // The pipe still contains the byte from the second
241 // signal and so wait won't block but won't return
242 // a signal.
243 recieved_signals = signals.wait();
244 assert_no_signals!(recieved_signals);
245 }
246
247 #[test]
248 #[serial]
is_closed_initially_returns_false()249 fn is_closed_initially_returns_false() {
250 let (_, controller) = setup_for_sigusr2();
251
252 assert!(!controller.is_closed());
253 }
254
255 #[test]
256 #[serial]
is_closed_returns_true_when_closed()257 fn is_closed_returns_true_when_closed() {
258 let (_, controller) = setup_for_sigusr2();
259 controller.close();
260
261 assert!(controller.is_closed());
262 }
263