nix/sys/
signal.rs

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