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