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
6use crate::errno::Errno;
7use crate::{Error, Result};
8use cfg_if::cfg_if;
9use std::fmt;
10use std::mem;
11#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
12use std::os::unix::io::RawFd;
13use std::ptr;
14use std::str::FromStr;
15
16#[cfg(not(any(
17 target_os = "fuchsia",
18 target_os = "openbsd",
19 target_os = "redox"
20)))]
21#[cfg(any(feature = "aio", feature = "signal"))]
22pub use self::sigevent::*;
23
24#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
25libc_enum! {
26 /// Types of operating system signals
27 // Currently there is only one definition of c_int in libc, as well as only one
28 // type for signal constants.
29 // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
30 // this is not (yet) possible.
31 #[repr(i32)]
32 #[non_exhaustive]
33 #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))]
34 pub enum Signal {
35 /// Hangup
36 SIGHUP,
37 /// Interrupt
38 SIGINT,
39 /// Quit
40 SIGQUIT,
41 /// Illegal instruction (not reset when caught)
42 SIGILL,
43 /// Trace trap (not reset when caught)
44 SIGTRAP,
45 /// Abort
46 SIGABRT,
47 /// Bus error
48 SIGBUS,
49 /// Floating point exception
50 SIGFPE,
51 /// Kill (cannot be caught or ignored)
52 SIGKILL,
53 /// User defined signal 1
54 SIGUSR1,
55 /// Segmentation violation
56 SIGSEGV,
57 /// User defined signal 2
58 SIGUSR2,
59 /// Write on a pipe with no one to read it
60 SIGPIPE,
61 /// Alarm clock
62 SIGALRM,
63 /// Software termination signal from kill
64 SIGTERM,
65 /// Stack fault (obsolete)
66 #[cfg(all(any(target_os = "android", target_os = "emscripten",
67 target_os = "fuchsia", target_os = "linux"),
68 not(any(target_arch = "mips", target_arch = "mips64",
69 target_arch = "sparc64"))))]
70 SIGSTKFLT,
71 /// To parent on child stop or exit
72 SIGCHLD,
73 /// Continue a stopped process
74 SIGCONT,
75 /// Sendable stop signal not from tty
76 SIGSTOP,
77 /// Stop signal from tty
78 SIGTSTP,
79 /// To readers pgrp upon background tty read
80 SIGTTIN,
81 /// Like TTIN if (tp->t_local&LTOSTOP)
82 SIGTTOU,
83 /// Urgent condition on IO channel
84 SIGURG,
85 /// Exceeded CPU time limit
86 SIGXCPU,
87 /// Exceeded file size limit
88 SIGXFSZ,
89 /// Virtual time alarm
90 SIGVTALRM,
91 /// Profiling time alarm
92 SIGPROF,
93 /// Window size changes
94 SIGWINCH,
95 /// Input/output possible signal
96 #[cfg(not(target_os = "haiku"))]
97 #[cfg_attr(docsrs, doc(cfg(all())))]
98 SIGIO,
99 #[cfg(any(target_os = "android", target_os = "emscripten",
100 target_os = "fuchsia", target_os = "linux",
101 target_os = "aix"))]
102 #[cfg_attr(docsrs, doc(cfg(all())))]
103 /// Power failure imminent.
104 SIGPWR,
105 /// Bad system call
106 SIGSYS,
107 #[cfg(not(any(target_os = "android", target_os = "emscripten",
108 target_os = "fuchsia", target_os = "linux",
109 target_os = "redox", target_os = "haiku")))]
110 #[cfg_attr(docsrs, doc(cfg(all())))]
111 /// Emulator trap
112 SIGEMT,
113 #[cfg(not(any(target_os = "android", target_os = "emscripten",
114 target_os = "fuchsia", target_os = "linux",
115 target_os = "redox", target_os = "haiku",
116 target_os = "aix")))]
117 #[cfg_attr(docsrs, doc(cfg(all())))]
118 /// Information request
119 SIGINFO,
120 }
121 impl TryFrom<i32>
122}
123
124#[cfg(feature = "signal")]
125impl FromStr for Signal {
126 type Err = Error;
127 fn from_str(s: &str) -> Result<Signal> {
128 Ok(match s {
129 "SIGHUP" => Signal::SIGHUP,
130 "SIGINT" => Signal::SIGINT,
131 "SIGQUIT" => Signal::SIGQUIT,
132 "SIGILL" => Signal::SIGILL,
133 "SIGTRAP" => Signal::SIGTRAP,
134 "SIGABRT" => Signal::SIGABRT,
135 "SIGBUS" => Signal::SIGBUS,
136 "SIGFPE" => Signal::SIGFPE,
137 "SIGKILL" => Signal::SIGKILL,
138 "SIGUSR1" => Signal::SIGUSR1,
139 "SIGSEGV" => Signal::SIGSEGV,
140 "SIGUSR2" => Signal::SIGUSR2,
141 "SIGPIPE" => Signal::SIGPIPE,
142 "SIGALRM" => Signal::SIGALRM,
143 "SIGTERM" => Signal::SIGTERM,
144 #[cfg(all(
145 any(
146 target_os = "android",
147 target_os = "emscripten",
148 target_os = "fuchsia",
149 target_os = "linux"
150 ),
151 not(any(
152 target_arch = "mips",
153 target_arch = "mips64",
154 target_arch = "sparc64"
155 ))
156 ))]
157 "SIGSTKFLT" => Signal::SIGSTKFLT,
158 "SIGCHLD" => Signal::SIGCHLD,
159 "SIGCONT" => Signal::SIGCONT,
160 "SIGSTOP" => Signal::SIGSTOP,
161 "SIGTSTP" => Signal::SIGTSTP,
162 "SIGTTIN" => Signal::SIGTTIN,
163 "SIGTTOU" => Signal::SIGTTOU,
164 "SIGURG" => Signal::SIGURG,
165 "SIGXCPU" => Signal::SIGXCPU,
166 "SIGXFSZ" => Signal::SIGXFSZ,
167 "SIGVTALRM" => Signal::SIGVTALRM,
168 "SIGPROF" => Signal::SIGPROF,
169 "SIGWINCH" => Signal::SIGWINCH,
170 #[cfg(not(target_os = "haiku"))]
171 "SIGIO" => Signal::SIGIO,
172 #[cfg(any(
173 target_os = "android",
174 target_os = "emscripten",
175 target_os = "fuchsia",
176 target_os = "linux"
177 ))]
178 "SIGPWR" => Signal::SIGPWR,
179 "SIGSYS" => Signal::SIGSYS,
180 #[cfg(not(any(
181 target_os = "android",
182 target_os = "emscripten",
183 target_os = "fuchsia",
184 target_os = "linux",
185 target_os = "redox",
186 target_os = "haiku"
187 )))]
188 "SIGEMT" => Signal::SIGEMT,
189 #[cfg(not(any(
190 target_os = "android",
191 target_os = "emscripten",
192 target_os = "fuchsia",
193 target_os = "linux",
194 target_os = "redox",
195 target_os = "aix",
196 target_os = "haiku"
197 )))]
198 "SIGINFO" => Signal::SIGINFO,
199 _ => return Err(Errno::EINVAL),
200 })
201 }
202}
203
204#[cfg(feature = "signal")]
205impl Signal {
206 /// Returns name of signal.
207 ///
208 /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
209 /// with difference that returned string is `'static`
210 /// and not bound to `self`'s lifetime.
211 pub const fn as_str(self) -> &'static str {
212 match self {
213 Signal::SIGHUP => "SIGHUP",
214 Signal::SIGINT => "SIGINT",
215 Signal::SIGQUIT => "SIGQUIT",
216 Signal::SIGILL => "SIGILL",
217 Signal::SIGTRAP => "SIGTRAP",
218 Signal::SIGABRT => "SIGABRT",
219 Signal::SIGBUS => "SIGBUS",
220 Signal::SIGFPE => "SIGFPE",
221 Signal::SIGKILL => "SIGKILL",
222 Signal::SIGUSR1 => "SIGUSR1",
223 Signal::SIGSEGV => "SIGSEGV",
224 Signal::SIGUSR2 => "SIGUSR2",
225 Signal::SIGPIPE => "SIGPIPE",
226 Signal::SIGALRM => "SIGALRM",
227 Signal::SIGTERM => "SIGTERM",
228 #[cfg(all(
229 any(
230 target_os = "android",
231 target_os = "emscripten",
232 target_os = "fuchsia",
233 target_os = "linux"
234 ),
235 not(any(
236 target_arch = "mips",
237 target_arch = "mips64",
238 target_arch = "sparc64"
239 ))
240 ))]
241 Signal::SIGSTKFLT => "SIGSTKFLT",
242 Signal::SIGCHLD => "SIGCHLD",
243 Signal::SIGCONT => "SIGCONT",
244 Signal::SIGSTOP => "SIGSTOP",
245 Signal::SIGTSTP => "SIGTSTP",
246 Signal::SIGTTIN => "SIGTTIN",
247 Signal::SIGTTOU => "SIGTTOU",
248 Signal::SIGURG => "SIGURG",
249 Signal::SIGXCPU => "SIGXCPU",
250 Signal::SIGXFSZ => "SIGXFSZ",
251 Signal::SIGVTALRM => "SIGVTALRM",
252 Signal::SIGPROF => "SIGPROF",
253 Signal::SIGWINCH => "SIGWINCH",
254 #[cfg(not(target_os = "haiku"))]
255 Signal::SIGIO => "SIGIO",
256 #[cfg(any(
257 target_os = "android",
258 target_os = "emscripten",
259 target_os = "fuchsia",
260 target_os = "aix",
261 target_os = "linux"
262 ))]
263 Signal::SIGPWR => "SIGPWR",
264 Signal::SIGSYS => "SIGSYS",
265 #[cfg(not(any(
266 target_os = "android",
267 target_os = "emscripten",
268 target_os = "fuchsia",
269 target_os = "linux",
270 target_os = "redox",
271 target_os = "haiku"
272 )))]
273 Signal::SIGEMT => "SIGEMT",
274 #[cfg(not(any(
275 target_os = "android",
276 target_os = "emscripten",
277 target_os = "fuchsia",
278 target_os = "linux",
279 target_os = "redox",
280 target_os = "aix",
281 target_os = "haiku"
282 )))]
283 Signal::SIGINFO => "SIGINFO",
284 }
285 }
286}
287
288#[cfg(feature = "signal")]
289impl AsRef<str> for Signal {
290 fn as_ref(&self) -> &str {
291 self.as_str()
292 }
293}
294
295#[cfg(feature = "signal")]
296impl fmt::Display for Signal {
297 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
298 f.write_str(self.as_ref())
299 }
300}
301
302#[cfg(feature = "signal")]
303pub use self::Signal::*;
304
305#[cfg(target_os = "redox")]
306#[cfg(feature = "signal")]
307const SIGNALS: [Signal; 29] = [
308 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
309 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
310 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
311 SIGPROF, SIGWINCH, SIGIO, SIGSYS,
312];
313#[cfg(target_os = "haiku")]
314#[cfg(feature = "signal")]
315const SIGNALS: [Signal; 28] = [
316 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
317 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
318 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
319 SIGPROF, SIGWINCH, SIGSYS,
320];
321#[cfg(all(
322 any(
323 target_os = "linux",
324 target_os = "android",
325 target_os = "emscripten",
326 target_os = "fuchsia"
327 ),
328 not(any(
329 target_arch = "mips",
330 target_arch = "mips64",
331 target_arch = "sparc64"
332 ))
333))]
334#[cfg(feature = "signal")]
335const SIGNALS: [Signal; 31] = [
336 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
337 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD,
338 SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
339 SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
340];
341#[cfg(all(
342 any(
343 target_os = "linux",
344 target_os = "android",
345 target_os = "emscripten",
346 target_os = "fuchsia"
347 ),
348 any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")
349))]
350#[cfg(feature = "signal")]
351const SIGNALS: [Signal; 30] = [
352 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
353 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
354 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
355 SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
356];
357#[cfg(target_os = "aix")]
358#[cfg(feature = "signal")]
359const SIGNALS: [Signal; 30] = [
360 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGEMT, SIGFPE, SIGKILL, SIGSEGV,
361 SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGPWR, SIGWINCH,
362 SIGURG, SIGPOLL, SIGIO, SIGSTOP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU,
363 SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP,
364];
365#[cfg(not(any(
366 target_os = "linux",
367 target_os = "android",
368 target_os = "fuchsia",
369 target_os = "emscripten",
370 target_os = "aix",
371 target_os = "redox",
372 target_os = "haiku"
373)))]
374#[cfg(feature = "signal")]
375const SIGNALS: [Signal; 31] = [
376 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
377 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
378 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
379 SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
380];
381
382feature! {
383#![feature = "signal"]
384
385#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
386/// Iterate through all signals defined by this operating system
387pub struct SignalIterator {
388 next: usize,
389}
390
391impl Iterator for SignalIterator {
392 type Item = Signal;
393
394 fn next(&mut self) -> Option<Signal> {
395 if self.next < SIGNALS.len() {
396 let next_signal = SIGNALS[self.next];
397 self.next += 1;
398 Some(next_signal)
399 } else {
400 None
401 }
402 }
403}
404
405impl Signal {
406 /// Iterate through all signals defined by this OS
407 pub const fn iterator() -> SignalIterator {
408 SignalIterator{next: 0}
409 }
410}
411
412/// Alias for [`SIGABRT`]
413pub const SIGIOT : Signal = SIGABRT;
414/// Alias for [`SIGIO`]
415#[cfg(not(target_os = "haiku"))]
416pub const SIGPOLL : Signal = SIGIO;
417/// Alias for [`SIGSYS`]
418pub const SIGUNUSED : Signal = SIGSYS;
419
420cfg_if! {
421 if #[cfg(target_os = "redox")] {
422 type SaFlags_t = libc::c_ulong;
423 } else if #[cfg(target_env = "uclibc")] {
424 type SaFlags_t = libc::c_ulong;
425 } else {
426 type SaFlags_t = libc::c_int;
427 }
428}
429}
430
431#[cfg(feature = "signal")]
432libc_bitflags! {
433 /// Controls the behavior of a [`SigAction`]
434 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
435 pub struct SaFlags: SaFlags_t {
436 /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
437 /// generated only when a child process exits, not when a child process
438 /// stops.
439 SA_NOCLDSTOP;
440 /// When catching a [`Signal::SIGCHLD`] signal, the system will not
441 /// create zombie processes when children of the calling process exit.
442 SA_NOCLDWAIT;
443 /// Further occurrences of the delivered signal are not masked during
444 /// the execution of the handler.
445 SA_NODEFER;
446 /// The system will deliver the signal to the process on a signal stack,
447 /// specified by each thread with sigaltstack(2).
448 SA_ONSTACK;
449 /// The handler is reset back to the default at the moment the signal is
450 /// delivered.
451 SA_RESETHAND;
452 /// Requests that certain system calls restart if interrupted by this
453 /// signal. See the man page for complete details.
454 SA_RESTART;
455 /// This flag is controlled internally by Nix.
456 SA_SIGINFO;
457 }
458}
459
460#[cfg(feature = "signal")]
461libc_enum! {
462 /// Specifies how certain functions should manipulate a signal mask
463 #[repr(i32)]
464 #[non_exhaustive]
465 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
466 pub enum SigmaskHow {
467 /// The new mask is the union of the current mask and the specified set.
468 SIG_BLOCK,
469 /// The new mask is the intersection of the current mask and the
470 /// complement of the specified set.
471 SIG_UNBLOCK,
472 /// The current mask is replaced by the specified set.
473 SIG_SETMASK,
474 }
475}
476
477feature! {
478#![feature = "signal"]
479
480use crate::unistd::Pid;
481use std::iter::Extend;
482use std::iter::FromIterator;
483use std::iter::IntoIterator;
484
485/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
486// We are using `transparent` here to be super sure that `SigSet`
487// is represented exactly like the `sigset_t` struct from C.
488#[repr(transparent)]
489#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
490pub struct SigSet {
491 sigset: libc::sigset_t
492}
493
494impl SigSet {
495 /// Initialize to include all signals.
496 #[doc(alias("sigfillset"))]
497 pub fn all() -> SigSet {
498 let mut sigset = mem::MaybeUninit::uninit();
499 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
500
501 unsafe{ SigSet { sigset: sigset.assume_init() } }
502 }
503
504 /// Initialize to include nothing.
505 #[doc(alias("sigemptyset"))]
506 pub fn empty() -> SigSet {
507 let mut sigset = mem::MaybeUninit::uninit();
508 let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
509
510 unsafe{ SigSet { sigset: sigset.assume_init() } }
511 }
512
513 /// Add the specified signal to the set.
514 #[doc(alias("sigaddset"))]
515 pub fn add(&mut self, signal: Signal) {
516 unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
517 }
518
519 /// Remove all signals from this set.
520 #[doc(alias("sigemptyset"))]
521 pub fn clear(&mut self) {
522 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
523 }
524
525 /// Remove the specified signal from this set.
526 #[doc(alias("sigdelset"))]
527 pub fn remove(&mut self, signal: Signal) {
528 unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
529 }
530
531 /// Return whether this set includes the specified signal.
532 #[doc(alias("sigismember"))]
533 pub fn contains(&self, signal: Signal) -> bool {
534 let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
535
536 match res {
537 1 => true,
538 0 => false,
539 _ => unreachable!("unexpected value from sigismember"),
540 }
541 }
542
543 /// Returns an iterator that yields the signals contained in this set.
544 pub fn iter(&self) -> SigSetIter<'_> {
545 self.into_iter()
546 }
547
548 /// Gets the currently blocked (masked) set of signals for the calling thread.
549 pub fn thread_get_mask() -> Result<SigSet> {
550 let mut oldmask = mem::MaybeUninit::uninit();
551 do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
552 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
553 }
554
555 /// Sets the set of signals as the signal mask for the calling thread.
556 pub fn thread_set_mask(&self) -> Result<()> {
557 pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
558 }
559
560 /// Adds the set of signals to the signal mask for the calling thread.
561 pub fn thread_block(&self) -> Result<()> {
562 pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
563 }
564
565 /// Removes the set of signals from the signal mask for the calling thread.
566 pub fn thread_unblock(&self) -> Result<()> {
567 pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
568 }
569
570 /// Sets the set of signals as the signal mask, and returns the old mask.
571 pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
572 let mut oldmask = mem::MaybeUninit::uninit();
573 do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
574 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
575 }
576
577 /// Suspends execution of the calling thread until one of the signals in the
578 /// signal mask becomes pending, and returns the accepted signal.
579 #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
580 #[cfg_attr(docsrs, doc(cfg(all())))]
581 pub fn wait(&self) -> Result<Signal> {
582 use std::convert::TryFrom;
583
584 let mut signum = mem::MaybeUninit::uninit();
585 let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
586
587 Errno::result(res).map(|_| unsafe {
588 Signal::try_from(signum.assume_init()).unwrap()
589 })
590 }
591
592 /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the
593 /// `libc::sigset_t` is already initialized.
594 ///
595 /// # Safety
596 ///
597 /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either
598 /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or
599 /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html).
600 /// Otherwise, the results are undefined.
601 pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
602 SigSet { sigset }
603 }
604}
605
606impl AsRef<libc::sigset_t> for SigSet {
607 fn as_ref(&self) -> &libc::sigset_t {
608 &self.sigset
609 }
610}
611
612// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available.
613impl Extend<Signal> for SigSet {
614 fn extend<T>(&mut self, iter: T)
615 where T: IntoIterator<Item = Signal> {
616 for signal in iter {
617 self.add(signal);
618 }
619 }
620}
621
622impl FromIterator<Signal> for SigSet {
623 fn from_iter<T>(iter: T) -> Self
624 where T: IntoIterator<Item = Signal> {
625 let mut sigset = SigSet::empty();
626 sigset.extend(iter);
627 sigset
628 }
629}
630
631/// Iterator for a [`SigSet`].
632///
633/// Call [`SigSet::iter`] to create an iterator.
634#[derive(Clone, Debug)]
635pub struct SigSetIter<'a> {
636 sigset: &'a SigSet,
637 inner: SignalIterator,
638}
639
640impl Iterator for SigSetIter<'_> {
641 type Item = Signal;
642 fn next(&mut self) -> Option<Signal> {
643 loop {
644 match self.inner.next() {
645 None => return None,
646 Some(signal) if self.sigset.contains(signal) => return Some(signal),
647 Some(_signal) => continue,
648 }
649 }
650 }
651}
652
653impl<'a> IntoIterator for &'a SigSet {
654 type Item = Signal;
655 type IntoIter = SigSetIter<'a>;
656 fn into_iter(self) -> Self::IntoIter {
657 SigSetIter { sigset: self, inner: Signal::iterator() }
658 }
659}
660
661/// A signal handler.
662#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
663pub enum SigHandler {
664 /// Default signal handling.
665 SigDfl,
666 /// Request that the signal be ignored.
667 SigIgn,
668 /// Use the given signal-catching function, which takes in the signal.
669 Handler(extern fn(libc::c_int)),
670 /// Use the given signal-catching function, which takes in the signal, information about how
671 /// the signal was generated, and a pointer to the threads `ucontext_t`.
672 #[cfg(not(target_os = "redox"))]
673 #[cfg_attr(docsrs, doc(cfg(all())))]
674 SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
675}
676
677/// Action to take on receipt of a signal. Corresponds to `sigaction`.
678#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
679pub struct SigAction {
680 sigaction: libc::sigaction
681}
682
683impl SigAction {
684 /// Creates a new action.
685 ///
686 /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
687 /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
688 /// the signal-catching function.
689 pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
690 #[cfg(not(target_os = "aix"))]
691 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
692 (*p).sa_sigaction = match handler {
693 SigHandler::SigDfl => libc::SIG_DFL,
694 SigHandler::SigIgn => libc::SIG_IGN,
695 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
696 #[cfg(not(target_os = "redox"))]
697 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
698 };
699 }
700
701 #[cfg(target_os = "aix")]
702 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
703 (*p).sa_union.__su_sigaction = match handler {
704 SigHandler::SigDfl => mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL),
705 SigHandler::SigIgn => mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN),
706 SigHandler::Handler(f) => mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f),
707 SigHandler::SigAction(f) => f,
708 };
709 }
710
711 let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
712 unsafe {
713 let p = s.as_mut_ptr();
714 install_sig(p, handler);
715 (*p).sa_flags = match handler {
716 #[cfg(not(target_os = "redox"))]
717 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
718 _ => (flags - SaFlags::SA_SIGINFO).bits(),
719 };
720 (*p).sa_mask = mask.sigset;
721
722 SigAction { sigaction: s.assume_init() }
723 }
724 }
725
726 /// Returns the flags set on the action.
727 pub fn flags(&self) -> SaFlags {
728 SaFlags::from_bits_truncate(self.sigaction.sa_flags)
729 }
730
731 /// Returns the set of signals that are blocked during execution of the action's
732 /// signal-catching function.
733 pub fn mask(&self) -> SigSet {
734 SigSet { sigset: self.sigaction.sa_mask }
735 }
736
737 /// Returns the action's handler.
738 #[cfg(not(target_os = "aix"))]
739 pub fn handler(&self) -> SigHandler {
740 match self.sigaction.sa_sigaction {
741 libc::SIG_DFL => SigHandler::SigDfl,
742 libc::SIG_IGN => SigHandler::SigIgn,
743 #[cfg(not(target_os = "redox"))]
744 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
745 SigHandler::SigAction(
746 // Safe for one of two reasons:
747 // * The SigHandler was created by SigHandler::new, in which
748 // case the pointer is correct, or
749 // * The SigHandler was created by signal or sigaction, which
750 // are unsafe functions, so the caller should've somehow
751 // ensured that it is correctly initialized.
752 unsafe{
753 *(&p as *const usize
754 as *const extern fn(_, _, _))
755 }
756 as extern fn(_, _, _)),
757 p => SigHandler::Handler(
758 // Safe for one of two reasons:
759 // * The SigHandler was created by SigHandler::new, in which
760 // case the pointer is correct, or
761 // * The SigHandler was created by signal or sigaction, which
762 // are unsafe functions, so the caller should've somehow
763 // ensured that it is correctly initialized.
764 unsafe{
765 *(&p as *const usize
766 as *const extern fn(libc::c_int))
767 }
768 as extern fn(libc::c_int)),
769 }
770 }
771
772 /// Returns the action's handler.
773 #[cfg(target_os = "aix")]
774 pub fn handler(&self) -> SigHandler {
775 unsafe {
776 match self.sigaction.sa_union.__su_sigaction as usize {
777 libc::SIG_DFL => SigHandler::SigDfl,
778 libc::SIG_IGN => SigHandler::SigIgn,
779 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
780 SigHandler::SigAction(
781 *(&p as *const usize
782 as *const extern fn(_, _, _))
783 as extern fn(_, _, _)),
784 p => SigHandler::Handler(
785 *(&p as *const usize
786 as *const extern fn(libc::c_int))
787 as extern fn(libc::c_int)),
788 }
789 }
790 }
791}
792
793/// Changes the action taken by a process on receipt of a specific signal.
794///
795/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
796/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
797///
798/// # Safety
799///
800/// * Signal handlers may be called at any point during execution, which limits
801/// what is safe to do in the body of the signal-catching function. Be certain
802/// to only make syscalls that are explicitly marked safe for signal handlers
803/// and only share global data using atomics.
804///
805/// * There is also no guarantee that the old signal handler was installed
806/// correctly. If it was installed by this crate, it will be. But if it was
807/// installed by, for example, C code, then there is no guarantee its function
808/// pointer is valid. In that case, this function effectively dereferences a
809/// raw pointer of unknown provenance.
810pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
811 let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
812
813 let res = libc::sigaction(signal as libc::c_int,
814 &sigaction.sigaction as *const libc::sigaction,
815 oldact.as_mut_ptr());
816
817 Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
818}
819
820/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
821///
822/// Installs `handler` for the given `signal`, returning the previous signal
823/// handler. `signal` should only be used following another call to `signal` or
824/// if the current handler is the default. The return value of `signal` is
825/// undefined after setting the handler with [`sigaction`][SigActionFn].
826///
827/// # Safety
828///
829/// If the pointer to the previous signal handler is invalid, undefined
830/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
831///
832/// # Examples
833///
834/// Ignore `SIGINT`:
835///
836/// ```no_run
837/// # use nix::sys::signal::{self, Signal, SigHandler};
838/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
839/// ```
840///
841/// Use a signal handler to set a flag variable:
842///
843/// ```no_run
844/// # use std::convert::TryFrom;
845/// # use std::sync::atomic::{AtomicBool, Ordering};
846/// # use nix::sys::signal::{self, Signal, SigHandler};
847/// static SIGNALED: AtomicBool = AtomicBool::new(false);
848///
849/// extern fn handle_sigint(signal: libc::c_int) {
850/// let signal = Signal::try_from(signal).unwrap();
851/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
852/// }
853///
854/// fn main() {
855/// let handler = SigHandler::Handler(handle_sigint);
856/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
857/// }
858/// ```
859///
860/// # Errors
861///
862/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
863/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
864///
865/// `signal` also returns any error from `libc::signal`, such as when an attempt
866/// is made to catch a signal that cannot be caught or to ignore a signal that
867/// cannot be ignored.
868///
869/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
870/// [SigActionStruct]: struct.SigAction.html
871/// [sigactionFn]: fn.sigaction.html
872pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
873 let signal = signal as libc::c_int;
874 let res = match handler {
875 SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
876 SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
877 SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
878 #[cfg(not(target_os = "redox"))]
879 SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
880 };
881 Errno::result(res).map(|oldhandler| {
882 match oldhandler {
883 libc::SIG_DFL => SigHandler::SigDfl,
884 libc::SIG_IGN => SigHandler::SigIgn,
885 p => SigHandler::Handler(
886 *(&p as *const usize
887 as *const extern fn(libc::c_int))
888 as extern fn(libc::c_int)),
889 }
890 })
891}
892
893fn do_pthread_sigmask(how: SigmaskHow,
894 set: Option<&SigSet>,
895 oldset: Option<*mut libc::sigset_t>) -> Result<()> {
896 if set.is_none() && oldset.is_none() {
897 return Ok(())
898 }
899
900 let res = unsafe {
901 // if set or oldset is None, pass in null pointers instead
902 libc::pthread_sigmask(how as libc::c_int,
903 set.map_or_else(ptr::null::<libc::sigset_t>,
904 |s| &s.sigset as *const libc::sigset_t),
905 oldset.unwrap_or(ptr::null_mut())
906 )
907 };
908
909 Errno::result(res).map(drop)
910}
911
912/// Manages the signal mask (set of blocked signals) for the calling thread.
913///
914/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
915/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
916/// and no modification will take place.
917///
918/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
919///
920/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
921/// and then it will be updated with `set`.
922///
923/// If both `set` and `oldset` is None, this function is a no-op.
924///
925/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
926/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
927pub fn pthread_sigmask(how: SigmaskHow,
928 set: Option<&SigSet>,
929 oldset: Option<&mut SigSet>) -> Result<()>
930{
931 do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
932}
933
934/// Examine and change blocked signals.
935///
936/// For more information see the [`sigprocmask` man
937/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
938pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
939 if set.is_none() && oldset.is_none() {
940 return Ok(())
941 }
942
943 let res = unsafe {
944 // if set or oldset is None, pass in null pointers instead
945 libc::sigprocmask(how as libc::c_int,
946 set.map_or_else(ptr::null::<libc::sigset_t>,
947 |s| &s.sigset as *const libc::sigset_t),
948 oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
949 |os| &mut os.sigset as *mut libc::sigset_t))
950 };
951
952 Errno::result(res).map(drop)
953}
954
955/// Send a signal to a process
956///
957/// # Arguments
958///
959/// * `pid` - Specifies which processes should receive the signal.
960/// - If positive, specifies an individual process.
961/// - If zero, the signal will be sent to all processes whose group
962/// ID is equal to the process group ID of the sender. This is a
963#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
964#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
965/// - If `-1` and the process has super-user privileges, the signal
966/// is sent to all processes exclusing system processes.
967/// - If less than `-1`, the signal is sent to all processes whose
968/// process group ID is equal to the absolute value of `pid`.
969/// * `signal` - Signal to send. If `None`, error checking is performed
970/// but no signal is actually sent.
971///
972/// See Also
973/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
974pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
975 let res = unsafe { libc::kill(pid.into(),
976 match signal.into() {
977 Some(s) => s as libc::c_int,
978 None => 0,
979 }) };
980
981 Errno::result(res).map(drop)
982}
983
984/// Send a signal to a process group
985///
986/// # Arguments
987///
988/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior
989/// is platform-specific.
990/// * `signal` - Signal to send. If `None`, `killpg` will only preform error
991/// checking and won't send any signal.
992///
993/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
994#[cfg(not(target_os = "fuchsia"))]
995pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
996 let res = unsafe { libc::killpg(pgrp.into(),
997 match signal.into() {
998 Some(s) => s as libc::c_int,
999 None => 0,
1000 }) };
1001
1002 Errno::result(res).map(drop)
1003}
1004
1005/// Send a signal to the current thread
1006///
1007/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
1008pub fn raise(signal: Signal) -> Result<()> {
1009 let res = unsafe { libc::raise(signal as libc::c_int) };
1010
1011 Errno::result(res).map(drop)
1012}
1013}
1014
1015feature! {
1016#![any(feature = "aio", feature = "signal")]
1017
1018/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1019#[cfg(target_os = "freebsd")]
1020pub type type_of_thread_id = libc::lwpid_t;
1021/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1022#[cfg(any(target_env = "gnu", target_env = "uclibc"))]
1023pub type type_of_thread_id = libc::pid_t;
1024
1025/// Specifies the notification method used by a [`SigEvent`]
1026// sigval is actually a union of a int and a void*. But it's never really used
1027// as a pointer, because neither libc nor the kernel ever dereference it. nix
1028// therefore presents it as an intptr_t, which is how kevent uses it.
1029#[cfg(not(any(target_os = "fuchsia", target_os = "openbsd", target_os = "redox")))]
1030#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1031pub enum SigevNotify {
1032 /// No notification will be delivered
1033 SigevNone,
1034 /// Notify by delivering a signal to the process.
1035 SigevSignal {
1036 /// Signal to deliver
1037 signal: Signal,
1038 /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1039 /// structure of the queued signal.
1040 si_value: libc::intptr_t
1041 },
1042 // Note: SIGEV_THREAD is not implemented, but could be if desired.
1043 /// Notify by delivering an event to a kqueue.
1044 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1045 #[cfg_attr(docsrs, doc(cfg(all())))]
1046 SigevKevent {
1047 /// File descriptor of the kqueue to notify.
1048 kq: RawFd,
1049 /// Will be contained in the kevent's `udata` field.
1050 udata: libc::intptr_t
1051 },
1052 /// Notify by delivering an event to a kqueue, with optional event flags set
1053 #[cfg(target_os = "freebsd")]
1054 #[cfg_attr(docsrs, doc(cfg(all())))]
1055 #[cfg(feature = "event")]
1056 SigevKeventFlags {
1057 /// File descriptor of the kqueue to notify.
1058 kq: RawFd,
1059 /// Will be contained in the kevent's `udata` field.
1060 udata: libc::intptr_t,
1061 /// Flags that will be set on the delivered event. See `kevent(2)`.
1062 flags: crate::sys::event::EventFlag
1063 },
1064 /// Notify by delivering a signal to a thread.
1065 #[cfg(any(
1066 target_os = "freebsd",
1067 target_env = "gnu",
1068 target_env = "uclibc",
1069 ))]
1070 #[cfg_attr(docsrs, doc(cfg(all())))]
1071 SigevThreadId {
1072 /// Signal to send
1073 signal: Signal,
1074 /// LWP ID of the thread to notify
1075 thread_id: type_of_thread_id,
1076 /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1077 /// structure of the queued signal.
1078 si_value: libc::intptr_t
1079 },
1080}
1081}
1082
1083#[cfg(not(any(
1084 target_os = "fuchsia",
1085 target_os = "openbsd",
1086 target_os = "redox"
1087)))]
1088#[cfg_attr(docsrs, doc(cfg(all())))]
1089mod sigevent {
1090 feature! {
1091 #![any(feature = "aio", feature = "signal")]
1092
1093 use std::mem;
1094 use super::SigevNotify;
1095
1096 #[cfg(target_os = "freebsd")]
1097 pub(crate) use ffi::sigevent as libc_sigevent;
1098 #[cfg(not(target_os = "freebsd"))]
1099 pub(crate) use libc::sigevent as libc_sigevent;
1100
1101 // For FreeBSD only, we define the C structure here. Because the structure
1102 // defined in libc isn't correct. The real sigevent contains union fields,
1103 // but libc could not represent those when sigevent was originally added, so
1104 // instead libc simply defined the most useful field. Now that Rust can
1105 // represent unions, there's a PR to libc to fix it. However, it's stuck
1106 // forever due to backwards compatibility concerns. Even though there's a
1107 // workaround, libc refuses to merge it. I think it's just too complicated
1108 // for them to want to think about right now, because that project is
1109 // short-staffed. So we define it here instead, so we won't have to wait on
1110 // libc.
1111 // https://github.com/rust-lang/libc/pull/2813
1112 #[cfg(target_os = "freebsd")]
1113 mod ffi {
1114 use std::{fmt, hash};
1115
1116 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1117 #[repr(C)]
1118 pub struct __c_anonymous_sigev_thread {
1119 pub _function: *mut libc::c_void, // Actually a function pointer
1120 pub _attribute: *mut libc::pthread_attr_t,
1121 }
1122 #[derive(Clone, Copy)]
1123 // This will never be used on its own, and its parent has a Debug impl,
1124 // so it doesn't need one.
1125 #[allow(missing_debug_implementations)]
1126 #[repr(C)]
1127 pub union __c_anonymous_sigev_un {
1128 pub _threadid: libc::__lwpid_t,
1129 pub _sigev_thread: __c_anonymous_sigev_thread,
1130 pub _kevent_flags: libc::c_ushort,
1131 __spare__: [libc::c_long; 8],
1132 }
1133
1134 #[derive(Clone, Copy)]
1135 #[repr(C)]
1136 pub struct sigevent {
1137 pub sigev_notify: libc::c_int,
1138 pub sigev_signo: libc::c_int,
1139 pub sigev_value: libc::sigval,
1140 pub _sigev_un: __c_anonymous_sigev_un,
1141 }
1142
1143 impl fmt::Debug for sigevent {
1144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1145 let mut ds = f.debug_struct("sigevent");
1146 ds.field("sigev_notify", &self.sigev_notify)
1147 .field("sigev_signo", &self.sigev_signo)
1148 .field("sigev_value", &self.sigev_value);
1149 // Safe because we check the sigev_notify discriminant
1150 unsafe {
1151 match self.sigev_notify {
1152 libc::SIGEV_KEVENT => {
1153 ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1154 }
1155 libc::SIGEV_THREAD_ID => {
1156 ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1157 }
1158 libc::SIGEV_THREAD => {
1159 ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1160 ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1161 }
1162 _ => ()
1163 };
1164 }
1165 ds.finish()
1166 }
1167 }
1168
1169 impl PartialEq for sigevent {
1170 fn eq(&self, other: &Self) -> bool {
1171 let mut equals = self.sigev_notify == other.sigev_notify;
1172 equals &= self.sigev_signo == other.sigev_signo;
1173 equals &= self.sigev_value == other.sigev_value;
1174 // Safe because we check the sigev_notify discriminant
1175 unsafe {
1176 match self.sigev_notify {
1177 libc::SIGEV_KEVENT => {
1178 equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1179 }
1180 libc::SIGEV_THREAD_ID => {
1181 equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1182 }
1183 libc::SIGEV_THREAD => {
1184 equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1185 }
1186 _ => /* The union field is don't care */ ()
1187 }
1188 }
1189 equals
1190 }
1191 }
1192
1193 impl Eq for sigevent {}
1194
1195 impl hash::Hash for sigevent {
1196 fn hash<H: hash::Hasher>(&self, s: &mut H) {
1197 self.sigev_notify.hash(s);
1198 self.sigev_signo.hash(s);
1199 self.sigev_value.hash(s);
1200 // Safe because we check the sigev_notify discriminant
1201 unsafe {
1202 match self.sigev_notify {
1203 libc::SIGEV_KEVENT => {
1204 self._sigev_un._kevent_flags.hash(s);
1205 }
1206 libc::SIGEV_THREAD_ID => {
1207 self._sigev_un._threadid.hash(s);
1208 }
1209 libc::SIGEV_THREAD => {
1210 self._sigev_un._sigev_thread.hash(s);
1211 }
1212 _ => /* The union field is don't care */ ()
1213 }
1214 }
1215 }
1216 }
1217 }
1218
1219 /// Used to request asynchronous notification of the completion of certain
1220 /// events, such as POSIX AIO and timers.
1221 #[repr(C)]
1222 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1223 // It can't be Copy on all platforms.
1224 #[allow(missing_copy_implementations)]
1225 pub struct SigEvent {
1226 sigevent: libc_sigevent
1227 }
1228
1229 impl SigEvent {
1230 /// **Note:** this constructor does not allow the user to set the
1231 /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD
1232 /// at least those flags don't do anything useful. That field is part of a
1233 /// union that shares space with the more genuinely useful fields.
1234 ///
1235 /// **Note:** This constructor also doesn't allow the caller to set the
1236 /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
1237 /// required for `SIGEV_THREAD`. That's considered ok because on no operating
1238 /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
1239 /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
1240 /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
1241 /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
1242 /// more genuinely useful `sigev_notify_thread_id`
1243 pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1244 let mut sev: libc_sigevent = unsafe { mem::zeroed() };
1245 match sigev_notify {
1246 SigevNotify::SigevNone => {
1247 sev.sigev_notify = libc::SIGEV_NONE;
1248 },
1249 SigevNotify::SigevSignal{signal, si_value} => {
1250 sev.sigev_notify = libc::SIGEV_SIGNAL;
1251 sev.sigev_signo = signal as libc::c_int;
1252 sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
1253 },
1254 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1255 SigevNotify::SigevKevent{kq, udata} => {
1256 sev.sigev_notify = libc::SIGEV_KEVENT;
1257 sev.sigev_signo = kq;
1258 sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1259 },
1260 #[cfg(target_os = "freebsd")]
1261 #[cfg(feature = "event")]
1262 SigevNotify::SigevKeventFlags{kq, udata, flags} => {
1263 sev.sigev_notify = libc::SIGEV_KEVENT;
1264 sev.sigev_signo = kq;
1265 sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1266 sev._sigev_un._kevent_flags = flags.bits();
1267 },
1268 #[cfg(target_os = "freebsd")]
1269 SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
1270 sev.sigev_notify = libc::SIGEV_THREAD_ID;
1271 sev.sigev_signo = signal as libc::c_int;
1272 sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1273 sev._sigev_un._threadid = thread_id;
1274 }
1275 #[cfg(any(target_env = "gnu", target_env = "uclibc"))]
1276 SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
1277 sev.sigev_notify = libc::SIGEV_THREAD_ID;
1278 sev.sigev_signo = signal as libc::c_int;
1279 sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1280 sev.sigev_notify_thread_id = thread_id;
1281 }
1282 }
1283 SigEvent{sigevent: sev}
1284 }
1285
1286 /// Return a copy of the inner structure
1287 #[cfg(target_os = "freebsd")]
1288 pub fn sigevent(&self) -> libc::sigevent {
1289 // Safe because they're really the same structure. See
1290 // https://github.com/rust-lang/libc/pull/2813
1291 unsafe {
1292 mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
1293 }
1294 }
1295
1296 /// Return a copy of the inner structure
1297 #[cfg(not(target_os = "freebsd"))]
1298 pub fn sigevent(&self) -> libc::sigevent {
1299 self.sigevent
1300 }
1301
1302 /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1303 #[cfg(target_os = "freebsd")]
1304 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1305 // Safe because they're really the same structure. See
1306 // https://github.com/rust-lang/libc/pull/2813
1307 &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1308 }
1309
1310 /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1311 #[cfg(not(target_os = "freebsd"))]
1312 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1313 &mut self.sigevent
1314 }
1315 }
1316
1317 impl<'a> From<&'a libc::sigevent> for SigEvent {
1318 #[cfg(target_os = "freebsd")]
1319 fn from(sigevent: &libc::sigevent) -> Self {
1320 // Safe because they're really the same structure. See
1321 // https://github.com/rust-lang/libc/pull/2813
1322 let sigevent = unsafe {
1323 mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1324 };
1325 SigEvent{ sigevent }
1326 }
1327 #[cfg(not(target_os = "freebsd"))]
1328 fn from(sigevent: &libc::sigevent) -> Self {
1329 SigEvent{ sigevent: *sigevent }
1330 }
1331 }
1332 }
1333}
1334
1335#[cfg(test)]
1336mod tests {
1337 use super::*;
1338 #[cfg(not(target_os = "redox"))]
1339 use std::thread;
1340
1341 #[test]
1342 fn test_contains() {
1343 let mut mask = SigSet::empty();
1344 mask.add(SIGUSR1);
1345
1346 assert!(mask.contains(SIGUSR1));
1347 assert!(!mask.contains(SIGUSR2));
1348
1349 let all = SigSet::all();
1350 assert!(all.contains(SIGUSR1));
1351 assert!(all.contains(SIGUSR2));
1352 }
1353
1354 #[test]
1355 fn test_clear() {
1356 let mut set = SigSet::all();
1357 set.clear();
1358 for signal in Signal::iterator() {
1359 assert!(!set.contains(signal));
1360 }
1361 }
1362
1363 #[test]
1364 fn test_from_str_round_trips() {
1365 for signal in Signal::iterator() {
1366 assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1367 assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1368 }
1369 }
1370
1371 #[test]
1372 fn test_from_str_invalid_value() {
1373 let errval = Err(Errno::EINVAL);
1374 assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1375 assert_eq!("kill".parse::<Signal>(), errval);
1376 assert_eq!("9".parse::<Signal>(), errval);
1377 }
1378
1379 #[test]
1380 fn test_extend() {
1381 let mut one_signal = SigSet::empty();
1382 one_signal.add(SIGUSR1);
1383
1384 let mut two_signals = SigSet::empty();
1385 two_signals.add(SIGUSR2);
1386 two_signals.extend(&one_signal);
1387
1388 assert!(two_signals.contains(SIGUSR1));
1389 assert!(two_signals.contains(SIGUSR2));
1390 }
1391
1392 #[test]
1393 #[cfg(not(target_os = "redox"))]
1394 fn test_thread_signal_set_mask() {
1395 thread::spawn(|| {
1396 let prev_mask = SigSet::thread_get_mask()
1397 .expect("Failed to get existing signal mask!");
1398
1399 let mut test_mask = prev_mask;
1400 test_mask.add(SIGUSR1);
1401
1402 test_mask.thread_set_mask().expect("assertion failed");
1403 let new_mask =
1404 SigSet::thread_get_mask().expect("Failed to get new mask!");
1405
1406 assert!(new_mask.contains(SIGUSR1));
1407 assert!(!new_mask.contains(SIGUSR2));
1408
1409 prev_mask
1410 .thread_set_mask()
1411 .expect("Failed to revert signal mask!");
1412 })
1413 .join()
1414 .unwrap();
1415 }
1416
1417 #[test]
1418 #[cfg(not(target_os = "redox"))]
1419 fn test_thread_signal_block() {
1420 thread::spawn(|| {
1421 let mut mask = SigSet::empty();
1422 mask.add(SIGUSR1);
1423
1424 mask.thread_block().expect("assertion failed");
1425
1426 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1427 })
1428 .join()
1429 .unwrap();
1430 }
1431
1432 #[test]
1433 #[cfg(not(target_os = "redox"))]
1434 fn test_thread_signal_unblock() {
1435 thread::spawn(|| {
1436 let mut mask = SigSet::empty();
1437 mask.add(SIGUSR1);
1438
1439 mask.thread_unblock().expect("assertion failed");
1440
1441 assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1442 })
1443 .join()
1444 .unwrap();
1445 }
1446
1447 #[test]
1448 #[cfg(not(target_os = "redox"))]
1449 fn test_thread_signal_swap() {
1450 thread::spawn(|| {
1451 let mut mask = SigSet::empty();
1452 mask.add(SIGUSR1);
1453 mask.thread_block().unwrap();
1454
1455 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1456
1457 let mut mask2 = SigSet::empty();
1458 mask2.add(SIGUSR2);
1459
1460 let oldmask =
1461 mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
1462
1463 assert!(oldmask.contains(SIGUSR1));
1464 assert!(!oldmask.contains(SIGUSR2));
1465
1466 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1467 })
1468 .join()
1469 .unwrap();
1470 }
1471
1472 #[test]
1473 fn test_from_and_into_iterator() {
1474 let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1475 let signals = sigset.into_iter().collect::<Vec<Signal>>();
1476 assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1477 }
1478
1479 #[test]
1480 #[cfg(not(target_os = "redox"))]
1481 fn test_sigaction() {
1482 thread::spawn(|| {
1483 extern "C" fn test_sigaction_handler(_: libc::c_int) {}
1484 extern "C" fn test_sigaction_action(
1485 _: libc::c_int,
1486 _: *mut libc::siginfo_t,
1487 _: *mut libc::c_void,
1488 ) {
1489 }
1490
1491 let handler_sig = SigHandler::Handler(test_sigaction_handler);
1492
1493 let flags =
1494 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
1495
1496 let mut mask = SigSet::empty();
1497 mask.add(SIGUSR1);
1498
1499 let action_sig = SigAction::new(handler_sig, flags, mask);
1500
1501 assert_eq!(
1502 action_sig.flags(),
1503 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
1504 );
1505 assert_eq!(action_sig.handler(), handler_sig);
1506
1507 mask = action_sig.mask();
1508 assert!(mask.contains(SIGUSR1));
1509 assert!(!mask.contains(SIGUSR2));
1510
1511 let handler_act = SigHandler::SigAction(test_sigaction_action);
1512 let action_act = SigAction::new(handler_act, flags, mask);
1513 assert_eq!(action_act.handler(), handler_act);
1514
1515 let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1516 assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1517
1518 let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1519 assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1520 })
1521 .join()
1522 .unwrap();
1523 }
1524
1525 #[test]
1526 #[cfg(not(target_os = "redox"))]
1527 fn test_sigwait() {
1528 thread::spawn(|| {
1529 let mut mask = SigSet::empty();
1530 mask.add(SIGUSR1);
1531 mask.add(SIGUSR2);
1532 mask.thread_block().unwrap();
1533
1534 raise(SIGUSR1).unwrap();
1535 assert_eq!(mask.wait().unwrap(), SIGUSR1);
1536 })
1537 .join()
1538 .unwrap();
1539 }
1540
1541 #[test]
1542 fn test_from_sigset_t_unchecked() {
1543 let src_set = SigSet::empty();
1544 let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1545
1546 for signal in Signal::iterator() {
1547 assert!(!set.contains(signal));
1548 }
1549
1550 let src_set = SigSet::all();
1551 let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1552
1553 for signal in Signal::iterator() {
1554 assert!(set.contains(signal));
1555 }
1556 }
1557}
1558