1 use nix::errno::Errno;
2 use nix::sys::signal::*;
3 use nix::unistd::*;
4 use std::hash::{Hash, Hasher};
5 use std::sync::atomic::{AtomicBool, Ordering};
6 #[cfg(not(target_os = "redox"))]
7 use std::thread;
8 
9 #[test]
test_kill_none()10 fn test_kill_none() {
11     kill(getpid(), None).expect("Should be able to send signal to myself.");
12 }
13 
14 #[test]
15 #[cfg(not(target_os = "fuchsia"))]
test_killpg_none()16 fn test_killpg_none() {
17     killpg(getpgrp(), None)
18         .expect("Should be able to send signal to my process group.");
19 }
20 
21 #[test]
test_old_sigaction_flags()22 fn test_old_sigaction_flags() {
23     let _m = crate::SIGNAL_MTX.lock();
24 
25     extern "C" fn handler(_: ::libc::c_int) {}
26     let act = SigAction::new(
27         SigHandler::Handler(handler),
28         SaFlags::empty(),
29         SigSet::empty(),
30     );
31     let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
32     let _flags = oact.flags();
33     let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
34     let _flags = oact.flags();
35 }
36 
37 #[test]
test_sigprocmask_noop()38 fn test_sigprocmask_noop() {
39     sigprocmask(SigmaskHow::SIG_BLOCK, None, None)
40         .expect("this should be an effective noop");
41 }
42 
43 #[test]
test_sigprocmask()44 fn test_sigprocmask() {
45     let _m = crate::SIGNAL_MTX.lock();
46 
47     // This needs to be a signal that rust doesn't use in the test harness.
48     const SIGNAL: Signal = Signal::SIGCHLD;
49 
50     let mut old_signal_set = SigSet::empty();
51     sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
52         .expect("expect to be able to retrieve old signals");
53 
54     // Make sure the old set doesn't contain the signal, otherwise the following
55     // test don't make sense.
56     assert!(
57         !old_signal_set.contains(SIGNAL),
58         "the {SIGNAL:?} signal is already blocked, please change to a \
59              different one"
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 {SIGNAL:?} to be blocked"
75     );
76 
77     // Reset the signal.
78     sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None)
79         .expect("expect to be able to block signals");
80 }
81 
82 static SIGNALED: AtomicBool = AtomicBool::new(false);
83 
test_sigaction_handler(signal: libc::c_int)84 extern "C" fn test_sigaction_handler(signal: libc::c_int) {
85     let signal = Signal::try_from(signal).unwrap();
86     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
87 }
88 
89 #[cfg(not(target_os = "redox"))]
test_sigaction_action( _: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void, )90 extern "C" fn test_sigaction_action(
91     _: libc::c_int,
92     _: *mut libc::siginfo_t,
93     _: *mut libc::c_void,
94 ) {
95 }
96 
97 #[test]
98 #[cfg(not(target_os = "redox"))]
test_signal_sigaction()99 fn test_signal_sigaction() {
100     let _m = crate::SIGNAL_MTX.lock();
101 
102     let action_handler = SigHandler::SigAction(test_sigaction_action);
103     assert_eq!(
104         unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(),
105         Errno::ENOTSUP
106     );
107 }
108 
109 #[test]
test_signal()110 fn test_signal() {
111     let _m = crate::SIGNAL_MTX.lock();
112 
113     unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
114     raise(Signal::SIGINT).unwrap();
115     assert_eq!(
116         unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
117         SigHandler::SigIgn
118     );
119 
120     let handler = SigHandler::Handler(test_sigaction_handler);
121     assert_eq!(
122         unsafe { signal(Signal::SIGINT, handler) }.unwrap(),
123         SigHandler::SigDfl
124     );
125     raise(Signal::SIGINT).unwrap();
126     assert!(SIGNALED.load(Ordering::Relaxed));
127 
128     #[cfg(not(solarish))]
129     assert_eq!(
130         unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
131         handler
132     );
133 
134     // System V based OSes (e.g. illumos and Solaris) always resets the
135     // disposition to SIG_DFL prior to calling the signal handler
136     #[cfg(solarish)]
137     assert_eq!(
138         unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
139         SigHandler::SigDfl
140     );
141 
142     // Restore default signal handler
143     unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
144 }
145 
146 #[test]
test_contains()147 fn test_contains() {
148     let mut mask = SigSet::empty();
149     mask.add(SIGUSR1);
150 
151     assert!(mask.contains(SIGUSR1));
152     assert!(!mask.contains(SIGUSR2));
153 
154     let all = SigSet::all();
155     assert!(all.contains(SIGUSR1));
156     assert!(all.contains(SIGUSR2));
157 }
158 
159 #[test]
test_clear()160 fn test_clear() {
161     let mut set = SigSet::all();
162     set.clear();
163     for signal in Signal::iterator() {
164         assert!(!set.contains(signal));
165     }
166 }
167 
168 #[test]
test_from_str_round_trips()169 fn test_from_str_round_trips() {
170     for signal in Signal::iterator() {
171         assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
172         assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
173     }
174 }
175 
176 #[test]
test_from_str_invalid_value()177 fn test_from_str_invalid_value() {
178     let errval = Err(Errno::EINVAL);
179     assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
180     assert_eq!("kill".parse::<Signal>(), errval);
181     assert_eq!("9".parse::<Signal>(), errval);
182 }
183 
184 #[test]
test_extend()185 fn test_extend() {
186     let mut one_signal = SigSet::empty();
187     one_signal.add(SIGUSR1);
188 
189     let mut two_signals = SigSet::empty();
190     two_signals.add(SIGUSR2);
191     two_signals.extend(&one_signal);
192 
193     assert!(two_signals.contains(SIGUSR1));
194     assert!(two_signals.contains(SIGUSR2));
195 }
196 
197 #[test]
198 #[cfg(not(target_os = "redox"))]
test_thread_signal_set_mask()199 fn test_thread_signal_set_mask() {
200     thread::spawn(|| {
201         let prev_mask = SigSet::thread_get_mask()
202             .expect("Failed to get existing signal mask!");
203 
204         let mut test_mask = prev_mask;
205         test_mask.add(SIGUSR1);
206 
207         test_mask.thread_set_mask().expect("assertion failed");
208         let new_mask =
209             SigSet::thread_get_mask().expect("Failed to get new mask!");
210 
211         assert!(new_mask.contains(SIGUSR1));
212         assert!(!new_mask.contains(SIGUSR2));
213 
214         prev_mask
215             .thread_set_mask()
216             .expect("Failed to revert signal mask!");
217     })
218     .join()
219     .unwrap();
220 }
221 
222 #[test]
223 #[cfg(not(target_os = "redox"))]
test_thread_signal_block()224 fn test_thread_signal_block() {
225     thread::spawn(|| {
226         let mut mask = SigSet::empty();
227         mask.add(SIGUSR1);
228 
229         mask.thread_block().expect("assertion failed");
230 
231         assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
232     })
233     .join()
234     .unwrap();
235 }
236 
237 #[test]
238 #[cfg(not(target_os = "redox"))]
test_thread_signal_unblock()239 fn test_thread_signal_unblock() {
240     thread::spawn(|| {
241         let mut mask = SigSet::empty();
242         mask.add(SIGUSR1);
243 
244         mask.thread_unblock().expect("assertion failed");
245 
246         assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
247     })
248     .join()
249     .unwrap();
250 }
251 
252 #[test]
253 #[cfg(not(target_os = "redox"))]
test_thread_signal_swap()254 fn test_thread_signal_swap() {
255     thread::spawn(|| {
256         let mut mask = SigSet::empty();
257         mask.add(SIGUSR1);
258         mask.thread_block().unwrap();
259 
260         assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
261 
262         let mut mask2 = SigSet::empty();
263         mask2.add(SIGUSR2);
264 
265         let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
266 
267         assert!(oldmask.contains(SIGUSR1));
268         assert!(!oldmask.contains(SIGUSR2));
269 
270         assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
271     })
272     .join()
273     .unwrap();
274 }
275 
276 #[test]
test_from_and_into_iterator()277 fn test_from_and_into_iterator() {
278     let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
279     let signals = sigset.into_iter().collect::<Vec<Signal>>();
280     assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
281 }
282 
283 #[test]
284 #[cfg(not(target_os = "redox"))]
test_sigaction()285 fn test_sigaction() {
286     thread::spawn(|| {
287         extern "C" fn test_sigaction_handler(_: libc::c_int) {}
288         extern "C" fn test_sigaction_action(
289             _: libc::c_int,
290             _: *mut libc::siginfo_t,
291             _: *mut libc::c_void,
292         ) {
293         }
294 
295         let handler_sig = SigHandler::Handler(test_sigaction_handler);
296 
297         let flags =
298             SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
299 
300         let mut mask = SigSet::empty();
301         mask.add(SIGUSR1);
302 
303         let action_sig = SigAction::new(handler_sig, flags, mask);
304 
305         assert_eq!(
306             action_sig.flags(),
307             SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
308         );
309         assert_eq!(action_sig.handler(), handler_sig);
310 
311         mask = action_sig.mask();
312         assert!(mask.contains(SIGUSR1));
313         assert!(!mask.contains(SIGUSR2));
314 
315         let handler_act = SigHandler::SigAction(test_sigaction_action);
316         let action_act = SigAction::new(handler_act, flags, mask);
317         assert_eq!(action_act.handler(), handler_act);
318 
319         let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
320         assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
321 
322         let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
323         assert_eq!(action_ign.handler(), SigHandler::SigIgn);
324     })
325     .join()
326     .unwrap();
327 }
328 
329 #[test]
330 #[cfg(not(target_os = "redox"))]
test_sigwait()331 fn test_sigwait() {
332     thread::spawn(|| {
333         let mut mask = SigSet::empty();
334         mask.add(SIGUSR1);
335         mask.add(SIGUSR2);
336         mask.thread_block().unwrap();
337 
338         raise(SIGUSR1).unwrap();
339         assert_eq!(mask.wait().unwrap(), SIGUSR1);
340     })
341     .join()
342     .unwrap();
343 }
344 
345 #[cfg(any(
346     bsd,
347     linux_android,
348     solarish,
349     target_os = "haiku",
350     target_os = "hurd",
351     target_os = "aix",
352     target_os = "fushsia"
353 ))]
354 #[test]
test_sigsuspend()355 fn test_sigsuspend() {
356     // This test change signal handler
357     let _m = crate::SIGNAL_MTX.lock();
358     static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false);
359     extern "C" fn test_sigsuspend_handler(_: libc::c_int) {
360         assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst));
361     }
362     thread::spawn(|| {
363         const SIGNAL: Signal = Signal::SIGUSR1;
364 
365         // Add signal mask to this thread
366         let mut signal_set = SigSet::empty();
367         signal_set.add(SIGNAL);
368         signal_set.thread_block().unwrap();
369 
370         // Set signal handler and save old one.
371         let act = SigAction::new(
372             SigHandler::Handler(test_sigsuspend_handler),
373             SaFlags::empty(),
374             SigSet::empty(),
375         );
376         let old_act = unsafe { sigaction(SIGNAL, &act) }
377             .expect("expect to be able to set new action and get old action");
378 
379         raise(SIGNAL).expect("expect be able to send signal");
380         // Now `SIGNAL` was sended but it is blocked.
381         let mut not_wait_set = SigSet::all();
382         not_wait_set.remove(SIGNAL);
383         // signal handler must run in SigSet::suspend()
384         assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst));
385         not_wait_set.suspend().unwrap();
386         assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst));
387 
388         // Restore the signal handler.
389         unsafe { sigaction(SIGNAL, &old_act) }
390             .expect("expect to be able to restore old action ");
391     })
392     .join()
393     .unwrap();
394 }
395 
396 #[test]
test_from_sigset_t_unchecked()397 fn test_from_sigset_t_unchecked() {
398     let src_set = SigSet::empty();
399     let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) };
400 
401     for signal in Signal::iterator() {
402         assert!(!set.contains(signal));
403     }
404 
405     let src_set = SigSet::all();
406     let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) };
407 
408     for signal in Signal::iterator() {
409         assert!(set.contains(signal));
410     }
411 }
412 
413 #[test]
test_eq_empty()414 fn test_eq_empty() {
415     let set0 = SigSet::empty();
416     let set1 = SigSet::empty();
417     assert_eq!(set0, set1);
418 }
419 
420 #[test]
test_eq_all()421 fn test_eq_all() {
422     let set0 = SigSet::all();
423     let set1 = SigSet::all();
424     assert_eq!(set0, set1);
425 }
426 
427 #[test]
test_hash_empty()428 fn test_hash_empty() {
429     use std::collections::hash_map::DefaultHasher;
430 
431     let set0 = SigSet::empty();
432     let mut h0 = DefaultHasher::new();
433     set0.hash(&mut h0);
434 
435     let set1 = SigSet::empty();
436     let mut h1 = DefaultHasher::new();
437     set1.hash(&mut h1);
438 
439     assert_eq!(h0.finish(), h1.finish());
440 }
441 
442 #[test]
test_hash_all()443 fn test_hash_all() {
444     use std::collections::hash_map::DefaultHasher;
445 
446     let set0 = SigSet::all();
447     let mut h0 = DefaultHasher::new();
448     set0.hash(&mut h0);
449 
450     let set1 = SigSet::all();
451     let mut h1 = DefaultHasher::new();
452     set1.hash(&mut h1);
453 
454     assert_eq!(h0.finish(), h1.finish());
455 }
456