1 // Portions of this file are Copyright 2014 The Rust Project Developers.
2 // See https://www.rust-lang.org/policies/licenses.
3
4 //! Operating system signals.
5
6 use crate::{Error, Result};
7 use crate::errno::Errno;
8 use crate::unistd::Pid;
9 use std::mem;
10 use std::fmt;
11 use std::str::FromStr;
12 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
13 use std::os::unix::io::RawFd;
14 use std::ptr;
15
16 #[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
17 pub use self::sigevent::*;
18
19 libc_enum!{
20 /// Types of operating system signals
21 // Currently there is only one definition of c_int in libc, as well as only one
22 // type for signal constants.
23 // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
24 // this is not (yet) possible.
25 #[repr(i32)]
26 #[non_exhaustive]
27 pub enum Signal {
28 /// Hangup
29 SIGHUP,
30 /// Interrupt
31 SIGINT,
32 /// Quit
33 SIGQUIT,
34 /// Illegal instruction (not reset when caught)
35 SIGILL,
36 /// Trace trap (not reset when caught)
37 SIGTRAP,
38 /// Abort
39 SIGABRT,
40 /// Bus error
41 SIGBUS,
42 /// Floating point exception
43 SIGFPE,
44 /// Kill (cannot be caught or ignored)
45 SIGKILL,
46 /// User defined signal 1
47 SIGUSR1,
48 /// Segmentation violation
49 SIGSEGV,
50 /// User defined signal 2
51 SIGUSR2,
52 /// Write on a pipe with no one to read it
53 SIGPIPE,
54 /// Alarm clock
55 SIGALRM,
56 /// Software termination signal from kill
57 SIGTERM,
58 /// Stack fault (obsolete)
59 #[cfg(all(any(target_os = "android", target_os = "emscripten",
60 target_os = "fuchsia", target_os = "linux"),
61 not(any(target_arch = "mips", target_arch = "mips64",
62 target_arch = "sparc64"))))]
63 SIGSTKFLT,
64 /// To parent on child stop or exit
65 SIGCHLD,
66 /// Continue a stopped process
67 SIGCONT,
68 /// Sendable stop signal not from tty
69 SIGSTOP,
70 /// Stop signal from tty
71 SIGTSTP,
72 /// To readers pgrp upon background tty read
73 SIGTTIN,
74 /// Like TTIN if (tp->t_local<OSTOP)
75 SIGTTOU,
76 /// Urgent condition on IO channel
77 SIGURG,
78 /// Exceeded CPU time limit
79 SIGXCPU,
80 /// Exceeded file size limit
81 SIGXFSZ,
82 /// Virtual time alarm
83 SIGVTALRM,
84 /// Profiling time alarm
85 SIGPROF,
86 /// Window size changes
87 SIGWINCH,
88 /// Input/output possible signal
89 SIGIO,
90 #[cfg(any(target_os = "android", target_os = "emscripten",
91 target_os = "fuchsia", target_os = "linux"))]
92 /// Power failure imminent.
93 SIGPWR,
94 /// Bad system call
95 SIGSYS,
96 #[cfg(not(any(target_os = "android", target_os = "emscripten",
97 target_os = "fuchsia", target_os = "linux",
98 target_os = "redox")))]
99 /// Emulator trap
100 SIGEMT,
101 #[cfg(not(any(target_os = "android", target_os = "emscripten",
102 target_os = "fuchsia", target_os = "linux",
103 target_os = "redox")))]
104 /// Information request
105 SIGINFO,
106 }
107 impl TryFrom<i32>
108 }
109
110 impl FromStr for Signal {
111 type Err = Error;
from_str(s: &str) -> Result<Signal>112 fn from_str(s: &str) -> Result<Signal> {
113 Ok(match s {
114 "SIGHUP" => Signal::SIGHUP,
115 "SIGINT" => Signal::SIGINT,
116 "SIGQUIT" => Signal::SIGQUIT,
117 "SIGILL" => Signal::SIGILL,
118 "SIGTRAP" => Signal::SIGTRAP,
119 "SIGABRT" => Signal::SIGABRT,
120 "SIGBUS" => Signal::SIGBUS,
121 "SIGFPE" => Signal::SIGFPE,
122 "SIGKILL" => Signal::SIGKILL,
123 "SIGUSR1" => Signal::SIGUSR1,
124 "SIGSEGV" => Signal::SIGSEGV,
125 "SIGUSR2" => Signal::SIGUSR2,
126 "SIGPIPE" => Signal::SIGPIPE,
127 "SIGALRM" => Signal::SIGALRM,
128 "SIGTERM" => Signal::SIGTERM,
129 #[cfg(all(any(target_os = "android", target_os = "emscripten",
130 target_os = "fuchsia", target_os = "linux"),
131 not(any(target_arch = "mips", target_arch = "mips64",
132 target_arch = "sparc64"))))]
133 "SIGSTKFLT" => Signal::SIGSTKFLT,
134 "SIGCHLD" => Signal::SIGCHLD,
135 "SIGCONT" => Signal::SIGCONT,
136 "SIGSTOP" => Signal::SIGSTOP,
137 "SIGTSTP" => Signal::SIGTSTP,
138 "SIGTTIN" => Signal::SIGTTIN,
139 "SIGTTOU" => Signal::SIGTTOU,
140 "SIGURG" => Signal::SIGURG,
141 "SIGXCPU" => Signal::SIGXCPU,
142 "SIGXFSZ" => Signal::SIGXFSZ,
143 "SIGVTALRM" => Signal::SIGVTALRM,
144 "SIGPROF" => Signal::SIGPROF,
145 "SIGWINCH" => Signal::SIGWINCH,
146 "SIGIO" => Signal::SIGIO,
147 #[cfg(any(target_os = "android", target_os = "emscripten",
148 target_os = "fuchsia", target_os = "linux"))]
149 "SIGPWR" => Signal::SIGPWR,
150 "SIGSYS" => Signal::SIGSYS,
151 #[cfg(not(any(target_os = "android", target_os = "emscripten",
152 target_os = "fuchsia", target_os = "linux",
153 target_os = "redox")))]
154 "SIGEMT" => Signal::SIGEMT,
155 #[cfg(not(any(target_os = "android", target_os = "emscripten",
156 target_os = "fuchsia", target_os = "linux",
157 target_os = "redox")))]
158 "SIGINFO" => Signal::SIGINFO,
159 _ => return Err(Errno::EINVAL),
160 })
161 }
162 }
163
164 impl Signal {
165 /// Returns name of signal.
166 ///
167 /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
168 /// with difference that returned string is `'static`
169 /// and not bound to `self`'s lifetime.
as_str(self) -> &'static str170 pub const fn as_str(self) -> &'static str {
171 match self {
172 Signal::SIGHUP => "SIGHUP",
173 Signal::SIGINT => "SIGINT",
174 Signal::SIGQUIT => "SIGQUIT",
175 Signal::SIGILL => "SIGILL",
176 Signal::SIGTRAP => "SIGTRAP",
177 Signal::SIGABRT => "SIGABRT",
178 Signal::SIGBUS => "SIGBUS",
179 Signal::SIGFPE => "SIGFPE",
180 Signal::SIGKILL => "SIGKILL",
181 Signal::SIGUSR1 => "SIGUSR1",
182 Signal::SIGSEGV => "SIGSEGV",
183 Signal::SIGUSR2 => "SIGUSR2",
184 Signal::SIGPIPE => "SIGPIPE",
185 Signal::SIGALRM => "SIGALRM",
186 Signal::SIGTERM => "SIGTERM",
187 #[cfg(all(any(target_os = "android", target_os = "emscripten",
188 target_os = "fuchsia", target_os = "linux"),
189 not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
190 Signal::SIGSTKFLT => "SIGSTKFLT",
191 Signal::SIGCHLD => "SIGCHLD",
192 Signal::SIGCONT => "SIGCONT",
193 Signal::SIGSTOP => "SIGSTOP",
194 Signal::SIGTSTP => "SIGTSTP",
195 Signal::SIGTTIN => "SIGTTIN",
196 Signal::SIGTTOU => "SIGTTOU",
197 Signal::SIGURG => "SIGURG",
198 Signal::SIGXCPU => "SIGXCPU",
199 Signal::SIGXFSZ => "SIGXFSZ",
200 Signal::SIGVTALRM => "SIGVTALRM",
201 Signal::SIGPROF => "SIGPROF",
202 Signal::SIGWINCH => "SIGWINCH",
203 Signal::SIGIO => "SIGIO",
204 #[cfg(any(target_os = "android", target_os = "emscripten",
205 target_os = "fuchsia", target_os = "linux"))]
206 Signal::SIGPWR => "SIGPWR",
207 Signal::SIGSYS => "SIGSYS",
208 #[cfg(not(any(target_os = "android", target_os = "emscripten",
209 target_os = "fuchsia", target_os = "linux",
210 target_os = "redox")))]
211 Signal::SIGEMT => "SIGEMT",
212 #[cfg(not(any(target_os = "android", target_os = "emscripten",
213 target_os = "fuchsia", target_os = "linux",
214 target_os = "redox")))]
215 Signal::SIGINFO => "SIGINFO",
216 }
217 }
218 }
219
220 impl AsRef<str> for Signal {
as_ref(&self) -> &str221 fn as_ref(&self) -> &str {
222 self.as_str()
223 }
224 }
225
226 impl fmt::Display for Signal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result227 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228 f.write_str(self.as_ref())
229 }
230 }
231
232 pub use self::Signal::*;
233
234 #[cfg(target_os = "redox")]
235 const SIGNALS: [Signal; 29] = [
236 SIGHUP,
237 SIGINT,
238 SIGQUIT,
239 SIGILL,
240 SIGTRAP,
241 SIGABRT,
242 SIGBUS,
243 SIGFPE,
244 SIGKILL,
245 SIGUSR1,
246 SIGSEGV,
247 SIGUSR2,
248 SIGPIPE,
249 SIGALRM,
250 SIGTERM,
251 SIGCHLD,
252 SIGCONT,
253 SIGSTOP,
254 SIGTSTP,
255 SIGTTIN,
256 SIGTTOU,
257 SIGURG,
258 SIGXCPU,
259 SIGXFSZ,
260 SIGVTALRM,
261 SIGPROF,
262 SIGWINCH,
263 SIGIO,
264 SIGSYS];
265 #[cfg(all(any(target_os = "linux", target_os = "android",
266 target_os = "emscripten", target_os = "fuchsia"),
267 not(any(target_arch = "mips", target_arch = "mips64",
268 target_arch = "sparc64"))))]
269 const SIGNALS: [Signal; 31] = [
270 SIGHUP,
271 SIGINT,
272 SIGQUIT,
273 SIGILL,
274 SIGTRAP,
275 SIGABRT,
276 SIGBUS,
277 SIGFPE,
278 SIGKILL,
279 SIGUSR1,
280 SIGSEGV,
281 SIGUSR2,
282 SIGPIPE,
283 SIGALRM,
284 SIGTERM,
285 SIGSTKFLT,
286 SIGCHLD,
287 SIGCONT,
288 SIGSTOP,
289 SIGTSTP,
290 SIGTTIN,
291 SIGTTOU,
292 SIGURG,
293 SIGXCPU,
294 SIGXFSZ,
295 SIGVTALRM,
296 SIGPROF,
297 SIGWINCH,
298 SIGIO,
299 SIGPWR,
300 SIGSYS];
301 #[cfg(all(any(target_os = "linux", target_os = "android",
302 target_os = "emscripten", target_os = "fuchsia"),
303 any(target_arch = "mips", target_arch = "mips64",
304 target_arch = "sparc64")))]
305 const SIGNALS: [Signal; 30] = [
306 SIGHUP,
307 SIGINT,
308 SIGQUIT,
309 SIGILL,
310 SIGTRAP,
311 SIGABRT,
312 SIGBUS,
313 SIGFPE,
314 SIGKILL,
315 SIGUSR1,
316 SIGSEGV,
317 SIGUSR2,
318 SIGPIPE,
319 SIGALRM,
320 SIGTERM,
321 SIGCHLD,
322 SIGCONT,
323 SIGSTOP,
324 SIGTSTP,
325 SIGTTIN,
326 SIGTTOU,
327 SIGURG,
328 SIGXCPU,
329 SIGXFSZ,
330 SIGVTALRM,
331 SIGPROF,
332 SIGWINCH,
333 SIGIO,
334 SIGPWR,
335 SIGSYS];
336 #[cfg(not(any(target_os = "linux", target_os = "android",
337 target_os = "fuchsia", target_os = "emscripten",
338 target_os = "redox")))]
339 const SIGNALS: [Signal; 31] = [
340 SIGHUP,
341 SIGINT,
342 SIGQUIT,
343 SIGILL,
344 SIGTRAP,
345 SIGABRT,
346 SIGBUS,
347 SIGFPE,
348 SIGKILL,
349 SIGUSR1,
350 SIGSEGV,
351 SIGUSR2,
352 SIGPIPE,
353 SIGALRM,
354 SIGTERM,
355 SIGCHLD,
356 SIGCONT,
357 SIGSTOP,
358 SIGTSTP,
359 SIGTTIN,
360 SIGTTOU,
361 SIGURG,
362 SIGXCPU,
363 SIGXFSZ,
364 SIGVTALRM,
365 SIGPROF,
366 SIGWINCH,
367 SIGIO,
368 SIGSYS,
369 SIGEMT,
370 SIGINFO];
371
372 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
373 /// Iterate through all signals defined by this operating system
374 pub struct SignalIterator {
375 next: usize,
376 }
377
378 impl Iterator for SignalIterator {
379 type Item = Signal;
380
next(&mut self) -> Option<Signal>381 fn next(&mut self) -> Option<Signal> {
382 if self.next < SIGNALS.len() {
383 let next_signal = SIGNALS[self.next];
384 self.next += 1;
385 Some(next_signal)
386 } else {
387 None
388 }
389 }
390 }
391
392 impl Signal {
393 /// Iterate through all signals defined by this OS
iterator() -> SignalIterator394 pub const fn iterator() -> SignalIterator {
395 SignalIterator{next: 0}
396 }
397 }
398
399 /// Alias for [`SIGABRT`]
400 pub const SIGIOT : Signal = SIGABRT;
401 /// Alias for [`SIGIO`]
402 pub const SIGPOLL : Signal = SIGIO;
403 /// Alias for [`SIGSYS`]
404 pub const SIGUNUSED : Signal = SIGSYS;
405
406 #[cfg(not(target_os = "redox"))]
407 type SaFlags_t = libc::c_int;
408 #[cfg(target_os = "redox")]
409 type SaFlags_t = libc::c_ulong;
410
411 libc_bitflags!{
412 /// Controls the behavior of a [`SigAction`]
413 pub struct SaFlags: SaFlags_t {
414 /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
415 /// generated only when a child process exits, not when a child process
416 /// stops.
417 SA_NOCLDSTOP;
418 /// When catching a [`Signal::SIGCHLD`] signal, the system will not
419 /// create zombie processes when children of the calling process exit.
420 SA_NOCLDWAIT;
421 /// Further occurrences of the delivered signal are not masked during
422 /// the execution of the handler.
423 SA_NODEFER;
424 /// The system will deliver the signal to the process on a signal stack,
425 /// specified by each thread with sigaltstack(2).
426 SA_ONSTACK;
427 /// The handler is reset back to the default at the moment the signal is
428 /// delivered.
429 SA_RESETHAND;
430 /// Requests that certain system calls restart if interrupted by this
431 /// signal. See the man page for complete details.
432 SA_RESTART;
433 /// This flag is controlled internally by Nix.
434 SA_SIGINFO;
435 }
436 }
437
438 libc_enum! {
439 /// Specifies how certain functions should manipulate a signal mask
440 #[repr(i32)]
441 #[non_exhaustive]
442 pub enum SigmaskHow {
443 /// The new mask is the union of the current mask and the specified set.
444 SIG_BLOCK,
445 /// The new mask is the intersection of the current mask and the
446 /// complement of the specified set.
447 SIG_UNBLOCK,
448 /// The current mask is replaced by the specified set.
449 SIG_SETMASK,
450 }
451 }
452
453 /// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
454 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
455 pub struct SigSet {
456 sigset: libc::sigset_t
457 }
458
459
460 impl SigSet {
461 /// Initialize to include all signals.
all() -> SigSet462 pub fn all() -> SigSet {
463 let mut sigset = mem::MaybeUninit::uninit();
464 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
465
466 unsafe{ SigSet { sigset: sigset.assume_init() } }
467 }
468
469 /// Initialize to include nothing.
empty() -> SigSet470 pub fn empty() -> SigSet {
471 let mut sigset = mem::MaybeUninit::uninit();
472 let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
473
474 unsafe{ SigSet { sigset: sigset.assume_init() } }
475 }
476
477 /// Add the specified signal to the set.
add(&mut self, signal: Signal)478 pub fn add(&mut self, signal: Signal) {
479 unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
480 }
481
482 /// Remove all signals from this set.
clear(&mut self)483 pub fn clear(&mut self) {
484 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
485 }
486
487 /// Remove the specified signal from this set.
remove(&mut self, signal: Signal)488 pub fn remove(&mut self, signal: Signal) {
489 unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
490 }
491
492 /// Return whether this set includes the specified signal.
contains(&self, signal: Signal) -> bool493 pub fn contains(&self, signal: Signal) -> bool {
494 let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
495
496 match res {
497 1 => true,
498 0 => false,
499 _ => unreachable!("unexpected value from sigismember"),
500 }
501 }
502
503 /// Merge all of `other`'s signals into this set.
504 // TODO: use libc::sigorset on supported operating systems.
extend(&mut self, other: &SigSet)505 pub fn extend(&mut self, other: &SigSet) {
506 for signal in Signal::iterator() {
507 if other.contains(signal) {
508 self.add(signal);
509 }
510 }
511 }
512
513 /// Gets the currently blocked (masked) set of signals for the calling thread.
thread_get_mask() -> Result<SigSet>514 pub fn thread_get_mask() -> Result<SigSet> {
515 let mut oldmask = mem::MaybeUninit::uninit();
516 do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
517 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
518 }
519
520 /// Sets the set of signals as the signal mask for the calling thread.
thread_set_mask(&self) -> Result<()>521 pub fn thread_set_mask(&self) -> Result<()> {
522 pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
523 }
524
525 /// Adds the set of signals to the signal mask for the calling thread.
thread_block(&self) -> Result<()>526 pub fn thread_block(&self) -> Result<()> {
527 pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
528 }
529
530 /// Removes the set of signals from the signal mask for the calling thread.
thread_unblock(&self) -> Result<()>531 pub fn thread_unblock(&self) -> Result<()> {
532 pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
533 }
534
535 /// Sets the set of signals as the signal mask, and returns the old mask.
thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet>536 pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
537 let mut oldmask = mem::MaybeUninit::uninit();
538 do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
539 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
540 }
541
542 /// Suspends execution of the calling thread until one of the signals in the
543 /// signal mask becomes pending, and returns the accepted signal.
544 #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
wait(&self) -> Result<Signal>545 pub fn wait(&self) -> Result<Signal> {
546 use std::convert::TryFrom;
547
548 let mut signum = mem::MaybeUninit::uninit();
549 let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
550
551 Errno::result(res).map(|_| unsafe {
552 Signal::try_from(signum.assume_init()).unwrap()
553 })
554 }
555 }
556
557 impl AsRef<libc::sigset_t> for SigSet {
as_ref(&self) -> &libc::sigset_t558 fn as_ref(&self) -> &libc::sigset_t {
559 &self.sigset
560 }
561 }
562
563 /// A signal handler.
564 #[allow(unknown_lints)]
565 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
566 pub enum SigHandler {
567 /// Default signal handling.
568 SigDfl,
569 /// Request that the signal be ignored.
570 SigIgn,
571 /// Use the given signal-catching function, which takes in the signal.
572 Handler(extern fn(libc::c_int)),
573 /// Use the given signal-catching function, which takes in the signal, information about how
574 /// the signal was generated, and a pointer to the threads `ucontext_t`.
575 #[cfg(not(target_os = "redox"))]
576 SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
577 }
578
579 /// Action to take on receipt of a signal. Corresponds to `sigaction`.
580 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
581 pub struct SigAction {
582 sigaction: libc::sigaction
583 }
584
585 impl SigAction {
586 /// Creates a new action.
587 ///
588 /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
589 /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
590 /// the signal-catching function.
new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction591 pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
592 #[cfg(target_os = "redox")]
593 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
594 (*p).sa_handler = match handler {
595 SigHandler::SigDfl => libc::SIG_DFL,
596 SigHandler::SigIgn => libc::SIG_IGN,
597 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
598 };
599 }
600
601 #[cfg(not(target_os = "redox"))]
602 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
603 (*p).sa_sigaction = match handler {
604 SigHandler::SigDfl => libc::SIG_DFL,
605 SigHandler::SigIgn => libc::SIG_IGN,
606 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
607 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
608 };
609 }
610
611 let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
612 unsafe {
613 let p = s.as_mut_ptr();
614 install_sig(p, handler);
615 (*p).sa_flags = match handler {
616 #[cfg(not(target_os = "redox"))]
617 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
618 _ => (flags - SaFlags::SA_SIGINFO).bits(),
619 };
620 (*p).sa_mask = mask.sigset;
621
622 SigAction { sigaction: s.assume_init() }
623 }
624 }
625
626 /// Returns the flags set on the action.
flags(&self) -> SaFlags627 pub fn flags(&self) -> SaFlags {
628 SaFlags::from_bits_truncate(self.sigaction.sa_flags)
629 }
630
631 /// Returns the set of signals that are blocked during execution of the action's
632 /// signal-catching function.
mask(&self) -> SigSet633 pub fn mask(&self) -> SigSet {
634 SigSet { sigset: self.sigaction.sa_mask }
635 }
636
637 /// Returns the action's handler.
638 #[cfg(not(target_os = "redox"))]
handler(&self) -> SigHandler639 pub fn handler(&self) -> SigHandler {
640 match self.sigaction.sa_sigaction {
641 libc::SIG_DFL => SigHandler::SigDfl,
642 libc::SIG_IGN => SigHandler::SigIgn,
643 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
644 SigHandler::SigAction(
645 // Safe for one of two reasons:
646 // * The SigHandler was created by SigHandler::new, in which
647 // case the pointer is correct, or
648 // * The SigHandler was created by signal or sigaction, which
649 // are unsafe functions, so the caller should've somehow
650 // ensured that it is correctly initialized.
651 unsafe{
652 *(&p as *const usize
653 as *const extern fn(_, _, _))
654 }
655 as extern fn(_, _, _)),
656 p => SigHandler::Handler(
657 // Safe for one of two reasons:
658 // * The SigHandler was created by SigHandler::new, in which
659 // case the pointer is correct, or
660 // * The SigHandler was created by signal or sigaction, which
661 // are unsafe functions, so the caller should've somehow
662 // ensured that it is correctly initialized.
663 unsafe{
664 *(&p as *const usize
665 as *const extern fn(libc::c_int))
666 }
667 as extern fn(libc::c_int)),
668 }
669 }
670
671 /// Returns the action's handler.
672 #[cfg(target_os = "redox")]
handler(&self) -> SigHandler673 pub fn handler(&self) -> SigHandler {
674 match self.sigaction.sa_handler {
675 libc::SIG_DFL => SigHandler::SigDfl,
676 libc::SIG_IGN => SigHandler::SigIgn,
677 p => SigHandler::Handler(
678 // Safe for one of two reasons:
679 // * The SigHandler was created by SigHandler::new, in which
680 // case the pointer is correct, or
681 // * The SigHandler was created by signal or sigaction, which
682 // are unsafe functions, so the caller should've somehow
683 // ensured that it is correctly initialized.
684 unsafe{
685 *(&p as *const usize
686 as *const extern fn(libc::c_int))
687 }
688 as extern fn(libc::c_int)),
689 }
690 }
691 }
692
693 /// Changes the action taken by a process on receipt of a specific signal.
694 ///
695 /// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
696 /// action for the given signal. If `sigaction` fails, no new signal handler is installed.
697 ///
698 /// # Safety
699 ///
700 /// * Signal handlers may be called at any point during execution, which limits
701 /// what is safe to do in the body of the signal-catching function. Be certain
702 /// to only make syscalls that are explicitly marked safe for signal handlers
703 /// and only share global data using atomics.
704 ///
705 /// * There is also no guarantee that the old signal handler was installed
706 /// correctly. If it was installed by this crate, it will be. But if it was
707 /// installed by, for example, C code, then there is no guarantee its function
708 /// pointer is valid. In that case, this function effectively dereferences a
709 /// raw pointer of unknown provenance.
sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction>710 pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
711 let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
712
713 let res = libc::sigaction(signal as libc::c_int,
714 &sigaction.sigaction as *const libc::sigaction,
715 oldact.as_mut_ptr());
716
717 Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
718 }
719
720 /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
721 ///
722 /// Installs `handler` for the given `signal`, returning the previous signal
723 /// handler. `signal` should only be used following another call to `signal` or
724 /// if the current handler is the default. The return value of `signal` is
725 /// undefined after setting the handler with [`sigaction`][SigActionFn].
726 ///
727 /// # Safety
728 ///
729 /// If the pointer to the previous signal handler is invalid, undefined
730 /// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
731 ///
732 /// # Examples
733 ///
734 /// Ignore `SIGINT`:
735 ///
736 /// ```no_run
737 /// # use nix::sys::signal::{self, Signal, SigHandler};
738 /// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
739 /// ```
740 ///
741 /// Use a signal handler to set a flag variable:
742 ///
743 /// ```no_run
744 /// # #[macro_use] extern crate lazy_static;
745 /// # use std::convert::TryFrom;
746 /// # use std::sync::atomic::{AtomicBool, Ordering};
747 /// # use nix::sys::signal::{self, Signal, SigHandler};
748 /// lazy_static! {
749 /// static ref SIGNALED: AtomicBool = AtomicBool::new(false);
750 /// }
751 ///
752 /// extern fn handle_sigint(signal: libc::c_int) {
753 /// let signal = Signal::try_from(signal).unwrap();
754 /// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
755 /// }
756 ///
757 /// fn main() {
758 /// let handler = SigHandler::Handler(handle_sigint);
759 /// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
760 /// }
761 /// ```
762 ///
763 /// # Errors
764 ///
765 /// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
766 /// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
767 ///
768 /// `signal` also returns any error from `libc::signal`, such as when an attempt
769 /// is made to catch a signal that cannot be caught or to ignore a signal that
770 /// cannot be ignored.
771 ///
772 /// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
773 /// [SigActionStruct]: struct.SigAction.html
774 /// [sigactionFn]: fn.sigaction.html
signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>775 pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
776 let signal = signal as libc::c_int;
777 let res = match handler {
778 SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
779 SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
780 SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
781 #[cfg(not(target_os = "redox"))]
782 SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
783 };
784 Errno::result(res).map(|oldhandler| {
785 match oldhandler {
786 libc::SIG_DFL => SigHandler::SigDfl,
787 libc::SIG_IGN => SigHandler::SigIgn,
788 p => SigHandler::Handler(
789 *(&p as *const usize
790 as *const extern fn(libc::c_int))
791 as extern fn(libc::c_int)),
792 }
793 })
794 }
795
do_pthread_sigmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<*mut libc::sigset_t>) -> Result<()>796 fn do_pthread_sigmask(how: SigmaskHow,
797 set: Option<&SigSet>,
798 oldset: Option<*mut libc::sigset_t>) -> Result<()> {
799 if set.is_none() && oldset.is_none() {
800 return Ok(())
801 }
802
803 let res = unsafe {
804 // if set or oldset is None, pass in null pointers instead
805 libc::pthread_sigmask(how as libc::c_int,
806 set.map_or_else(ptr::null::<libc::sigset_t>,
807 |s| &s.sigset as *const libc::sigset_t),
808 oldset.unwrap_or(ptr::null_mut())
809 )
810 };
811
812 Errno::result(res).map(drop)
813 }
814
815 /// Manages the signal mask (set of blocked signals) for the calling thread.
816 ///
817 /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
818 /// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
819 /// and no modification will take place.
820 ///
821 /// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
822 ///
823 /// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
824 /// and then it will be updated with `set`.
825 ///
826 /// If both `set` and `oldset` is None, this function is a no-op.
827 ///
828 /// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
829 /// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
pthread_sigmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()>830 pub fn pthread_sigmask(how: SigmaskHow,
831 set: Option<&SigSet>,
832 oldset: Option<&mut SigSet>) -> Result<()>
833 {
834 do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
835 }
836
837 /// Examine and change blocked signals.
838 ///
839 /// For more informations see the [`sigprocmask` man
840 /// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()>841 pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
842 if set.is_none() && oldset.is_none() {
843 return Ok(())
844 }
845
846 let res = unsafe {
847 // if set or oldset is None, pass in null pointers instead
848 libc::sigprocmask(how as libc::c_int,
849 set.map_or_else(ptr::null::<libc::sigset_t>,
850 |s| &s.sigset as *const libc::sigset_t),
851 oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
852 |os| &mut os.sigset as *mut libc::sigset_t))
853 };
854
855 Errno::result(res).map(drop)
856 }
857
858 /// Send a signal to a process
859 ///
860 /// # Arguments
861 ///
862 /// * `pid` - Specifies which processes should receive the signal.
863 /// - If positive, specifies an individual process
864 /// - If zero, the signal will be sent to all processes whose group
865 /// ID is equal to the process group ID of the sender. This is a
866 /// variant of [`killpg`].
867 /// - If `-1` and the process has super-user privileges, the signal
868 /// is sent to all processes exclusing system processes.
869 /// - If less than `-1`, the signal is sent to all processes whose
870 /// process group ID is equal to the absolute value of `pid`.
871 /// * `signal` - Signal to send. If `None`, error checking is performed
872 /// but no signal is actually sent.
873 ///
874 /// See Also
875 /// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()>876 pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
877 let res = unsafe { libc::kill(pid.into(),
878 match signal.into() {
879 Some(s) => s as libc::c_int,
880 None => 0,
881 }) };
882
883 Errno::result(res).map(drop)
884 }
885
886 /// Send a signal to a process group
887 ///
888 /// # Arguments
889 ///
890 /// * `pgrp` - Process group to signal. If less then or equal 1, the behavior
891 /// is platform-specific.
892 /// * `signal` - Signal to send. If `None`, `killpg` will only preform error
893 /// checking and won't send any signal.
894 ///
895 /// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
896 #[cfg(not(target_os = "fuchsia"))]
killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()>897 pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
898 let res = unsafe { libc::killpg(pgrp.into(),
899 match signal.into() {
900 Some(s) => s as libc::c_int,
901 None => 0,
902 }) };
903
904 Errno::result(res).map(drop)
905 }
906
907 /// Send a signal to the current thread
908 ///
909 /// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
raise(signal: Signal) -> Result<()>910 pub fn raise(signal: Signal) -> Result<()> {
911 let res = unsafe { libc::raise(signal as libc::c_int) };
912
913 Errno::result(res).map(drop)
914 }
915
916
917 /// Identifies a thread for [`SigevNotify::SigevThreadId`]
918 #[cfg(target_os = "freebsd")]
919 pub type type_of_thread_id = libc::lwpid_t;
920 /// Identifies a thread for [`SigevNotify::SigevThreadId`]
921 #[cfg(target_os = "linux")]
922 pub type type_of_thread_id = libc::pid_t;
923
924 /// Specifies the notification method used by a [`SigEvent`]
925 // sigval is actually a union of a int and a void*. But it's never really used
926 // as a pointer, because neither libc nor the kernel ever dereference it. nix
927 // therefore presents it as an intptr_t, which is how kevent uses it.
928 #[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
929 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
930 pub enum SigevNotify {
931 /// No notification will be delivered
932 SigevNone,
933 /// Notify by delivering a signal to the process.
934 SigevSignal {
935 /// Signal to deliver
936 signal: Signal,
937 /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
938 /// structure of the queued signal.
939 si_value: libc::intptr_t
940 },
941 // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
942 // expose a way to set the union members needed by SIGEV_THREAD.
943 /// Notify by delivering an event to a kqueue.
944 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
945 SigevKevent {
946 /// File descriptor of the kqueue to notify.
947 kq: RawFd,
948 /// Will be contained in the kevent's `udata` field.
949 udata: libc::intptr_t
950 },
951 /// Notify by delivering a signal to a thread.
952 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
953 SigevThreadId {
954 /// Signal to send
955 signal: Signal,
956 /// LWP ID of the thread to notify
957 thread_id: type_of_thread_id,
958 /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
959 /// structure of the queued signal.
960 si_value: libc::intptr_t
961 },
962 }
963
964 #[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
965 mod sigevent {
966 use std::mem;
967 use std::ptr;
968 use super::SigevNotify;
969 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
970 use super::type_of_thread_id;
971
972 /// Used to request asynchronous notification of the completion of certain
973 /// events, such as POSIX AIO and timers.
974 #[repr(C)]
975 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
976 pub struct SigEvent {
977 sigevent: libc::sigevent
978 }
979
980 impl SigEvent {
981 /// **Note:** this constructor does not allow the user to set the
982 /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD
983 /// at least those flags don't do anything useful. That field is part of a
984 /// union that shares space with the more genuinely useful fields.
985 ///
986 /// **Note:** This constructor also doesn't allow the caller to set the
987 /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
988 /// required for `SIGEV_THREAD`. That's considered ok because on no operating
989 /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
990 /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
991 /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
992 /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
993 /// more genuinely useful `sigev_notify_thread_id`
994 // Allow invalid_value warning on Fuchsia only.
995 // See https://github.com/nix-rust/nix/issues/1441
996 #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
new(sigev_notify: SigevNotify) -> SigEvent997 pub fn new(sigev_notify: SigevNotify) -> SigEvent {
998 let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
999 sev.sigev_notify = match sigev_notify {
1000 SigevNotify::SigevNone => libc::SIGEV_NONE,
1001 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
1002 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1003 SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
1004 #[cfg(target_os = "freebsd")]
1005 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1006 #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
1007 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1008 #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
1009 SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined
1010 };
1011 sev.sigev_signo = match sigev_notify {
1012 SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
1013 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1014 SigevNotify::SigevKevent{ kq, ..} => kq,
1015 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1016 SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
1017 _ => 0
1018 };
1019 sev.sigev_value.sival_ptr = match sigev_notify {
1020 SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
1021 SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
1022 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1023 SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
1024 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1025 SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
1026 };
1027 SigEvent::set_tid(&mut sev, &sigev_notify);
1028 SigEvent{sigevent: sev}
1029 }
1030
1031 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify)1032 fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1033 sev.sigev_notify_thread_id = match *sigev_notify {
1034 SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1035 _ => 0 as type_of_thread_id
1036 };
1037 }
1038
1039 #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify)1040 fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1041 }
1042
1043 /// Return a copy of the inner structure
sigevent(&self) -> libc::sigevent1044 pub fn sigevent(&self) -> libc::sigevent {
1045 self.sigevent
1046 }
1047 }
1048
1049 impl<'a> From<&'a libc::sigevent> for SigEvent {
from(sigevent: &libc::sigevent) -> Self1050 fn from(sigevent: &libc::sigevent) -> Self {
1051 SigEvent{ sigevent: *sigevent }
1052 }
1053 }
1054 }
1055
1056 #[cfg(test)]
1057 mod tests {
1058 #[cfg(not(target_os = "redox"))]
1059 use std::thread;
1060 use super::*;
1061
1062 #[test]
test_contains()1063 fn test_contains() {
1064 let mut mask = SigSet::empty();
1065 mask.add(SIGUSR1);
1066
1067 assert!(mask.contains(SIGUSR1));
1068 assert!(!mask.contains(SIGUSR2));
1069
1070 let all = SigSet::all();
1071 assert!(all.contains(SIGUSR1));
1072 assert!(all.contains(SIGUSR2));
1073 }
1074
1075 #[test]
test_clear()1076 fn test_clear() {
1077 let mut set = SigSet::all();
1078 set.clear();
1079 for signal in Signal::iterator() {
1080 assert!(!set.contains(signal));
1081 }
1082 }
1083
1084 #[test]
test_from_str_round_trips()1085 fn test_from_str_round_trips() {
1086 for signal in Signal::iterator() {
1087 assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1088 assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1089 }
1090 }
1091
1092 #[test]
test_from_str_invalid_value()1093 fn test_from_str_invalid_value() {
1094 let errval = Err(Errno::EINVAL);
1095 assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1096 assert_eq!("kill".parse::<Signal>(), errval);
1097 assert_eq!("9".parse::<Signal>(), errval);
1098 }
1099
1100 #[test]
test_extend()1101 fn test_extend() {
1102 let mut one_signal = SigSet::empty();
1103 one_signal.add(SIGUSR1);
1104
1105 let mut two_signals = SigSet::empty();
1106 two_signals.add(SIGUSR2);
1107 two_signals.extend(&one_signal);
1108
1109 assert!(two_signals.contains(SIGUSR1));
1110 assert!(two_signals.contains(SIGUSR2));
1111 }
1112
1113 #[test]
1114 #[cfg(not(target_os = "redox"))]
test_thread_signal_set_mask()1115 fn test_thread_signal_set_mask() {
1116 thread::spawn(|| {
1117 let prev_mask = SigSet::thread_get_mask()
1118 .expect("Failed to get existing signal mask!");
1119
1120 let mut test_mask = prev_mask;
1121 test_mask.add(SIGUSR1);
1122
1123 assert!(test_mask.thread_set_mask().is_ok());
1124 let new_mask = SigSet::thread_get_mask()
1125 .expect("Failed to get new mask!");
1126
1127 assert!(new_mask.contains(SIGUSR1));
1128 assert!(!new_mask.contains(SIGUSR2));
1129
1130 prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
1131 }).join().unwrap();
1132 }
1133
1134 #[test]
1135 #[cfg(not(target_os = "redox"))]
test_thread_signal_block()1136 fn test_thread_signal_block() {
1137 thread::spawn(|| {
1138 let mut mask = SigSet::empty();
1139 mask.add(SIGUSR1);
1140
1141 assert!(mask.thread_block().is_ok());
1142
1143 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1144 }).join().unwrap();
1145 }
1146
1147 #[test]
1148 #[cfg(not(target_os = "redox"))]
test_thread_signal_unblock()1149 fn test_thread_signal_unblock() {
1150 thread::spawn(|| {
1151 let mut mask = SigSet::empty();
1152 mask.add(SIGUSR1);
1153
1154 assert!(mask.thread_unblock().is_ok());
1155
1156 assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1157 }).join().unwrap();
1158 }
1159
1160 #[test]
1161 #[cfg(not(target_os = "redox"))]
test_thread_signal_swap()1162 fn test_thread_signal_swap() {
1163 thread::spawn(|| {
1164 let mut mask = SigSet::empty();
1165 mask.add(SIGUSR1);
1166 mask.thread_block().unwrap();
1167
1168 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1169
1170 let mut mask2 = SigSet::empty();
1171 mask2.add(SIGUSR2);
1172
1173 let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
1174 .unwrap();
1175
1176 assert!(oldmask.contains(SIGUSR1));
1177 assert!(!oldmask.contains(SIGUSR2));
1178
1179 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1180 }).join().unwrap();
1181 }
1182
1183 #[test]
1184 #[cfg(not(target_os = "redox"))]
test_sigaction()1185 fn test_sigaction() {
1186 thread::spawn(|| {
1187 extern fn test_sigaction_handler(_: libc::c_int) {}
1188 extern fn test_sigaction_action(_: libc::c_int,
1189 _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
1190
1191 let handler_sig = SigHandler::Handler(test_sigaction_handler);
1192
1193 let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
1194 SaFlags::SA_SIGINFO;
1195
1196 let mut mask = SigSet::empty();
1197 mask.add(SIGUSR1);
1198
1199 let action_sig = SigAction::new(handler_sig, flags, mask);
1200
1201 assert_eq!(action_sig.flags(),
1202 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
1203 assert_eq!(action_sig.handler(), handler_sig);
1204
1205 mask = action_sig.mask();
1206 assert!(mask.contains(SIGUSR1));
1207 assert!(!mask.contains(SIGUSR2));
1208
1209 let handler_act = SigHandler::SigAction(test_sigaction_action);
1210 let action_act = SigAction::new(handler_act, flags, mask);
1211 assert_eq!(action_act.handler(), handler_act);
1212
1213 let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1214 assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1215
1216 let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1217 assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1218 }).join().unwrap();
1219 }
1220
1221 #[test]
1222 #[cfg(not(target_os = "redox"))]
test_sigwait()1223 fn test_sigwait() {
1224 thread::spawn(|| {
1225 let mut mask = SigSet::empty();
1226 mask.add(SIGUSR1);
1227 mask.add(SIGUSR2);
1228 mask.thread_block().unwrap();
1229
1230 raise(SIGUSR1).unwrap();
1231 assert_eq!(mask.wait().unwrap(), SIGUSR1);
1232 }).join().unwrap();
1233 }
1234 }
1235