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 = "fushsia"
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#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
757pub struct SigAction {
758    sigaction: libc::sigaction
759}
760
761impl SigAction {
762    /// Creates a new action.
763    ///
764    /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
765    /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
766    /// the signal-catching function.
767    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
768        #[cfg(not(target_os = "aix"))]
769        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
770            unsafe {
771                 (*p).sa_sigaction = match handler {
772                    SigHandler::SigDfl => libc::SIG_DFL,
773                    SigHandler::SigIgn => libc::SIG_IGN,
774                    SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
775                    #[cfg(not(target_os = "redox"))]
776                    SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
777                };
778            }
779        }
780
781        #[cfg(target_os = "aix")]
782        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
783            unsafe {
784                (*p).sa_union.__su_sigaction = match handler {
785                    SigHandler::SigDfl => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL) },
786                    SigHandler::SigIgn => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN) },
787                    SigHandler::Handler(f) => unsafe { mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f) },
788                    SigHandler::SigAction(f) => f,
789                };
790            }
791        }
792
793        let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
794        unsafe {
795            let p = s.as_mut_ptr();
796            install_sig(p, handler);
797            (*p).sa_flags = match handler {
798                #[cfg(not(target_os = "redox"))]
799                SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
800                _ => (flags - SaFlags::SA_SIGINFO).bits(),
801            };
802            (*p).sa_mask = mask.sigset;
803
804            SigAction { sigaction: s.assume_init() }
805        }
806    }
807
808    /// Returns the flags set on the action.
809    pub fn flags(&self) -> SaFlags {
810        SaFlags::from_bits_truncate(self.sigaction.sa_flags)
811    }
812
813    /// Returns the set of signals that are blocked during execution of the action's
814    /// signal-catching function.
815    pub fn mask(&self) -> SigSet {
816        SigSet { sigset: self.sigaction.sa_mask }
817    }
818
819    /// Returns the action's handler.
820    #[cfg(not(target_os = "aix"))]
821    pub fn handler(&self) -> SigHandler {
822        match self.sigaction.sa_sigaction {
823            libc::SIG_DFL => SigHandler::SigDfl,
824            libc::SIG_IGN => SigHandler::SigIgn,
825            #[cfg(not(target_os = "redox"))]
826            p if self.flags().contains(SaFlags::SA_SIGINFO) =>
827                SigHandler::SigAction(
828                // Safe for one of two reasons:
829                // * The SigHandler was created by SigHandler::new, in which
830                //   case the pointer is correct, or
831                // * The SigHandler was created by signal or sigaction, which
832                //   are unsafe functions, so the caller should've somehow
833                //   ensured that it is correctly initialized.
834                unsafe{
835                    *(&p as *const usize
836                         as *const extern fn(_, _, _))
837                }
838                as extern fn(_, _, _)),
839            p => SigHandler::Handler(
840                // Safe for one of two reasons:
841                // * The SigHandler was created by SigHandler::new, in which
842                //   case the pointer is correct, or
843                // * The SigHandler was created by signal or sigaction, which
844                //   are unsafe functions, so the caller should've somehow
845                //   ensured that it is correctly initialized.
846                unsafe{
847                    *(&p as *const usize
848                         as *const extern fn(libc::c_int))
849                }
850                as extern fn(libc::c_int)),
851        }
852    }
853
854    /// Returns the action's handler.
855    #[cfg(target_os = "aix")]
856    pub fn handler(&self) -> SigHandler {
857        unsafe {
858        match self.sigaction.sa_union.__su_sigaction as usize {
859            libc::SIG_DFL => SigHandler::SigDfl,
860            libc::SIG_IGN => SigHandler::SigIgn,
861            p if self.flags().contains(SaFlags::SA_SIGINFO) =>
862                SigHandler::SigAction(
863                    *(&p as *const usize
864                         as *const extern fn(_, _, _))
865                as extern fn(_, _, _)),
866            p => SigHandler::Handler(
867                    *(&p as *const usize
868                         as *const extern fn(libc::c_int))
869                as extern fn(libc::c_int)),
870        }
871        }
872    }
873}
874
875/// Changes the action taken by a process on receipt of a specific signal.
876///
877/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
878/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
879///
880/// # Safety
881///
882/// * Signal handlers may be called at any point during execution, which limits
883///   what is safe to do in the body of the signal-catching function. Be certain
884///   to only make syscalls that are explicitly marked safe for signal handlers
885///   and only share global data using atomics.
886///
887/// * There is also no guarantee that the old signal handler was installed
888///   correctly.  If it was installed by this crate, it will be.  But if it was
889///   installed by, for example, C code, then there is no guarantee its function
890///   pointer is valid.  In that case, this function effectively dereferences a
891///   raw pointer of unknown provenance.
892pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
893    let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
894
895    let res = unsafe { libc::sigaction(signal as libc::c_int,
896                              &sigaction.sigaction as *const libc::sigaction,
897                              oldact.as_mut_ptr()) };
898
899    Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } })
900}
901
902/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
903///
904/// Installs `handler` for the given `signal`, returning the previous signal
905/// handler. `signal` should only be used following another call to `signal` or
906/// if the current handler is the default. The return value of `signal` is
907/// undefined after setting the handler with [`sigaction`][SigActionFn].
908///
909/// # Safety
910///
911/// If the pointer to the previous signal handler is invalid, undefined
912/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
913///
914/// # Examples
915///
916/// Ignore `SIGINT`:
917///
918/// ```no_run
919/// # use nix::sys::signal::{self, Signal, SigHandler};
920/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
921/// ```
922///
923/// Use a signal handler to set a flag variable:
924///
925/// ```no_run
926/// # use std::convert::TryFrom;
927/// # use std::sync::atomic::{AtomicBool, Ordering};
928/// # use nix::sys::signal::{self, Signal, SigHandler};
929/// static SIGNALED: AtomicBool = AtomicBool::new(false);
930///
931/// extern fn handle_sigint(signal: libc::c_int) {
932///     let signal = Signal::try_from(signal).unwrap();
933///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
934/// }
935///
936/// fn main() {
937///     let handler = SigHandler::Handler(handle_sigint);
938///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
939/// }
940/// ```
941///
942/// # Errors
943///
944/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
945/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
946///
947/// `signal` also returns any error from `libc::signal`, such as when an attempt
948/// is made to catch a signal that cannot be caught or to ignore a signal that
949/// cannot be ignored.
950///
951/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
952/// [SigActionStruct]: struct.SigAction.html
953/// [sigactionFn]: fn.sigaction.html
954pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
955    let signal = signal as libc::c_int;
956    let res = match handler {
957        SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) },
958        SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) },
959        SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) },
960        #[cfg(not(target_os = "redox"))]
961        SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
962    };
963    Errno::result(res).map(|oldhandler| {
964        match oldhandler {
965            libc::SIG_DFL => SigHandler::SigDfl,
966            libc::SIG_IGN => SigHandler::SigIgn,
967            p => SigHandler::Handler(
968                unsafe { *(&p as *const usize as *const extern fn(libc::c_int)) } as extern fn(libc::c_int)),
969        }
970    })
971}
972
973fn do_pthread_sigmask(how: SigmaskHow,
974                       set: Option<&SigSet>,
975                       oldset: Option<*mut libc::sigset_t>) -> Result<()> {
976    if set.is_none() && oldset.is_none() {
977        return Ok(())
978    }
979
980    let res = unsafe {
981        // if set or oldset is None, pass in null pointers instead
982        libc::pthread_sigmask(how as libc::c_int,
983                             set.map_or_else(ptr::null::<libc::sigset_t>,
984                                             |s| &s.sigset as *const libc::sigset_t),
985                             oldset.unwrap_or(ptr::null_mut())
986                             )
987    };
988
989    Errno::result(res).map(drop)
990}
991
992/// Manages the signal mask (set of blocked signals) for the calling thread.
993///
994/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
995/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
996/// and no modification will take place.
997///
998/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
999///
1000/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
1001/// and then it will be updated with `set`.
1002///
1003/// If both `set` and `oldset` is None, this function is a no-op.
1004///
1005/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
1006/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
1007pub fn pthread_sigmask(how: SigmaskHow,
1008                       set: Option<&SigSet>,
1009                       oldset: Option<&mut SigSet>) -> Result<()>
1010{
1011    do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
1012}
1013
1014/// Examine and change blocked signals.
1015///
1016/// For more information see the [`sigprocmask` man
1017/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
1018pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
1019    if set.is_none() && oldset.is_none() {
1020        return Ok(())
1021    }
1022
1023    let res = unsafe {
1024        // if set or oldset is None, pass in null pointers instead
1025        libc::sigprocmask(how as libc::c_int,
1026                          set.map_or_else(ptr::null::<libc::sigset_t>,
1027                                          |s| &s.sigset as *const libc::sigset_t),
1028                          oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
1029                                             |os| &mut os.sigset as *mut libc::sigset_t))
1030    };
1031
1032    Errno::result(res).map(drop)
1033}
1034
1035/// Send a signal to a process
1036///
1037/// # Arguments
1038///
1039/// * `pid` -    Specifies which processes should receive the signal.
1040///   - If positive, specifies an individual process.
1041///   - If zero, the signal will be sent to all processes whose group
1042///     ID is equal to the process group ID of the sender.  This is a
1043#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
1044#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
1045///   - If `-1` and the process has super-user privileges, the signal
1046///     is sent to all processes exclusing system processes.
1047///   - If less than `-1`, the signal is sent to all processes whose
1048///     process group ID is equal to the absolute value of `pid`.
1049/// * `signal` - Signal to send. If `None`, error checking is performed
1050///              but no signal is actually sent.
1051///
1052/// See Also
1053/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
1054pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
1055    let res = unsafe { libc::kill(pid.into(),
1056                                  match signal.into() {
1057                                      Some(s) => s as libc::c_int,
1058                                      None => 0,
1059                                  }) };
1060
1061    Errno::result(res).map(drop)
1062}
1063
1064/// Send a signal to a process group
1065///
1066/// # Arguments
1067///
1068/// * `pgrp` -   Process group to signal.  If less then or equal 1, the behavior
1069///              is platform-specific.
1070/// * `signal` - Signal to send. If `None`, `killpg` will only preform error
1071///              checking and won't send any signal.
1072///
1073/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
1074#[cfg(not(target_os = "fuchsia"))]
1075pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
1076    let res = unsafe { libc::killpg(pgrp.into(),
1077                                  match signal.into() {
1078                                      Some(s) => s as libc::c_int,
1079                                      None => 0,
1080                                  }) };
1081
1082    Errno::result(res).map(drop)
1083}
1084
1085/// Send a signal to the current thread
1086///
1087/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
1088pub fn raise(signal: Signal) -> Result<()> {
1089    let res = unsafe { libc::raise(signal as libc::c_int) };
1090
1091    Errno::result(res).map(drop)
1092}
1093}
1094
1095feature! {
1096#![any(feature = "aio", feature = "signal")]
1097
1098/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1099#[cfg(target_os = "freebsd")]
1100pub type type_of_thread_id = libc::lwpid_t;
1101/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1102#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))]
1103pub type type_of_thread_id = libc::pid_t;
1104
1105/// Specifies the notification method used by a [`SigEvent`]
1106// sigval is actually a union of a int and a void*.  But it's never really used
1107// as a pointer, because neither libc nor the kernel ever dereference it.  nix
1108// therefore presents it as an intptr_t, which is how kevent uses it.
1109#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))]
1110#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1111pub enum SigevNotify {
1112    /// No notification will be delivered
1113    SigevNone,
1114    /// Notify by delivering a signal to the process.
1115    SigevSignal {
1116        /// Signal to deliver
1117        signal: Signal,
1118        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1119        /// structure of the queued signal.
1120        si_value: libc::intptr_t
1121    },
1122    // Note: SIGEV_THREAD is not implemented, but could be if desired.
1123    /// Notify by delivering an event to a kqueue.
1124    #[cfg(freebsdlike)]
1125    SigevKevent {
1126        /// File descriptor of the kqueue to notify.
1127        kq: RawFd,
1128        /// Will be contained in the kevent's `udata` field.
1129        udata: libc::intptr_t
1130    },
1131    /// Notify by delivering an event to a kqueue, with optional event flags set
1132    #[cfg(target_os = "freebsd")]
1133    #[cfg(feature = "event")]
1134    SigevKeventFlags {
1135        /// File descriptor of the kqueue to notify.
1136        kq: RawFd,
1137        /// Will be contained in the kevent's `udata` field.
1138        udata: libc::intptr_t,
1139        /// Flags that will be set on the delivered event.  See `kevent(2)`.
1140        flags: crate::sys::event::EventFlag
1141    },
1142    /// Notify by delivering a signal to a thread.
1143    #[cfg(any(
1144            target_os = "freebsd",
1145            target_env = "gnu",
1146            target_env = "uclibc",
1147    ))]
1148    SigevThreadId {
1149        /// Signal to send
1150        signal: Signal,
1151        /// LWP ID of the thread to notify
1152        thread_id: type_of_thread_id,
1153        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1154        /// structure of the queued signal.
1155        si_value: libc::intptr_t
1156    },
1157}
1158}
1159
1160#[cfg(not(any(
1161    target_os = "fuchsia",
1162    target_os = "hurd",
1163    target_os = "openbsd",
1164    target_os = "redox"
1165)))]
1166mod sigevent {
1167    feature! {
1168    #![any(feature = "aio", feature = "signal")]
1169
1170    use std::mem;
1171    use super::SigevNotify;
1172
1173    #[cfg(target_os = "freebsd")]
1174    pub(crate) use ffi::sigevent as libc_sigevent;
1175    #[cfg(not(target_os = "freebsd"))]
1176    pub(crate) use libc::sigevent as libc_sigevent;
1177
1178    // For FreeBSD only, we define the C structure here.  Because the structure
1179    // defined in libc isn't correct.  The real sigevent contains union fields,
1180    // but libc could not represent those when sigevent was originally added, so
1181    // instead libc simply defined the most useful field.  Now that Rust can
1182    // represent unions, there's a PR to libc to fix it.  However, it's stuck
1183    // forever due to backwards compatibility concerns.  Even though there's a
1184    // workaround, libc refuses to merge it.  I think it's just too complicated
1185    // for them to want to think about right now, because that project is
1186    // short-staffed.  So we define it here instead, so we won't have to wait on
1187    // libc.
1188    // https://github.com/rust-lang/libc/pull/2813
1189    #[cfg(target_os = "freebsd")]
1190    mod ffi {
1191        use std::{fmt, hash};
1192
1193        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1194        #[repr(C)]
1195        pub struct __c_anonymous_sigev_thread {
1196            pub _function: *mut libc::c_void,   // Actually a function pointer
1197            pub _attribute: *mut libc::pthread_attr_t,
1198        }
1199        #[derive(Clone, Copy)]
1200        // This will never be used on its own, and its parent has a Debug impl,
1201        // so it doesn't need one.
1202        #[allow(missing_debug_implementations)]
1203        #[repr(C)]
1204        pub union __c_anonymous_sigev_un {
1205            pub _threadid: libc::__lwpid_t,
1206            pub _sigev_thread: __c_anonymous_sigev_thread,
1207            pub _kevent_flags: libc::c_ushort,
1208            __spare__: [libc::c_long; 8],
1209        }
1210
1211        #[derive(Clone, Copy)]
1212        #[repr(C)]
1213        pub struct sigevent {
1214            pub sigev_notify: libc::c_int,
1215            pub sigev_signo: libc::c_int,
1216            pub sigev_value: libc::sigval,
1217            pub _sigev_un: __c_anonymous_sigev_un,
1218        }
1219
1220        impl fmt::Debug for sigevent {
1221            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1222                let mut ds = f.debug_struct("sigevent");
1223                ds.field("sigev_notify", &self.sigev_notify)
1224                    .field("sigev_signo", &self.sigev_signo)
1225                    .field("sigev_value", &self.sigev_value);
1226                // Safe because we check the sigev_notify discriminant
1227                unsafe {
1228                    match self.sigev_notify {
1229                        libc::SIGEV_KEVENT => {
1230                            ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1231                        }
1232                        libc::SIGEV_THREAD_ID => {
1233                            ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1234                        }
1235                        libc::SIGEV_THREAD => {
1236                            ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1237                            ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1238                        }
1239                        _ => ()
1240                    };
1241                }
1242                ds.finish()
1243            }
1244        }
1245
1246        impl PartialEq for sigevent {
1247            fn eq(&self, other: &Self) -> bool {
1248                let mut equals = self.sigev_notify == other.sigev_notify;
1249                equals &= self.sigev_signo == other.sigev_signo;
1250                equals &= self.sigev_value == other.sigev_value;
1251                // Safe because we check the sigev_notify discriminant
1252                unsafe {
1253                    match self.sigev_notify {
1254                        libc::SIGEV_KEVENT => {
1255                            equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1256                        }
1257                        libc::SIGEV_THREAD_ID => {
1258                            equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1259                        }
1260                        libc::SIGEV_THREAD => {
1261                            equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1262                        }
1263                        _ => /* The union field is don't care */ ()
1264                    }
1265                }
1266                equals
1267            }
1268        }
1269
1270        impl Eq for sigevent {}
1271
1272        impl hash::Hash for sigevent {
1273            fn hash<H: hash::Hasher>(&self, s: &mut H) {
1274                self.sigev_notify.hash(s);
1275                self.sigev_signo.hash(s);
1276                self.sigev_value.hash(s);
1277                // Safe because we check the sigev_notify discriminant
1278                unsafe {
1279                    match self.sigev_notify {
1280                        libc::SIGEV_KEVENT => {
1281                            self._sigev_un._kevent_flags.hash(s);
1282                        }
1283                        libc::SIGEV_THREAD_ID => {
1284                            self._sigev_un._threadid.hash(s);
1285                        }
1286                        libc::SIGEV_THREAD => {
1287                            self._sigev_un._sigev_thread.hash(s);
1288                        }
1289                        _ => /* The union field is don't care */ ()
1290                    }
1291                }
1292            }
1293        }
1294    }
1295
1296    /// Used to request asynchronous notification of the completion of certain
1297    /// events, such as POSIX AIO and timers.
1298    #[repr(C)]
1299    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1300    // It can't be Copy on all platforms.
1301    #[allow(missing_copy_implementations)]
1302    pub struct SigEvent {
1303        sigevent: libc_sigevent
1304    }
1305
1306    impl SigEvent {
1307        /// **Note:** this constructor does not allow the user to set the
1308        /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
1309        /// at least those flags don't do anything useful.  That field is part of a
1310        /// union that shares space with the more genuinely useful fields.
1311        ///
1312        /// **Note:** This constructor also doesn't allow the caller to set the
1313        /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
1314        /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
1315        /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
1316        /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
1317        /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
1318        /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
1319        /// more genuinely useful `sigev_notify_thread_id`
1320        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1321            let mut sev: libc_sigevent = unsafe { mem::zeroed() };
1322            match sigev_notify {
1323                SigevNotify::SigevNone => {
1324                    sev.sigev_notify = libc::SIGEV_NONE;
1325                },
1326                SigevNotify::SigevSignal{signal, si_value} => {
1327                    sev.sigev_notify = libc::SIGEV_SIGNAL;
1328                    sev.sigev_signo = signal as libc::c_int;
1329                    sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
1330                },
1331                #[cfg(freebsdlike)]
1332                SigevNotify::SigevKevent{kq, udata} => {
1333                    sev.sigev_notify = libc::SIGEV_KEVENT;
1334                    sev.sigev_signo = kq;
1335                    sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1336                },
1337                #[cfg(target_os = "freebsd")]
1338                #[cfg(feature = "event")]
1339                SigevNotify::SigevKeventFlags{kq, udata, flags} => {
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                    sev._sigev_un._kevent_flags = flags.bits();
1344                },
1345                #[cfg(target_os = "freebsd")]
1346                SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
1347                    sev.sigev_notify = libc::SIGEV_THREAD_ID;
1348                    sev.sigev_signo = signal as libc::c_int;
1349                    sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1350                    sev._sigev_un._threadid = thread_id;
1351                }
1352                #[cfg(any(target_env = "gnu", target_env = "uclibc"))]
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_notify_thread_id = thread_id;
1358                }
1359            }
1360            SigEvent{sigevent: sev}
1361        }
1362
1363        /// Return a copy of the inner structure
1364        #[cfg(target_os = "freebsd")]
1365        pub fn sigevent(&self) -> libc::sigevent {
1366            // Safe because they're really the same structure.  See
1367            // https://github.com/rust-lang/libc/pull/2813
1368            unsafe {
1369                mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
1370            }
1371        }
1372
1373        /// Return a copy of the inner structure
1374        #[cfg(not(target_os = "freebsd"))]
1375        pub fn sigevent(&self) -> libc::sigevent {
1376            self.sigevent
1377        }
1378
1379        /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1380        #[cfg(target_os = "freebsd")]
1381        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1382            // Safe because they're really the same structure.  See
1383            // https://github.com/rust-lang/libc/pull/2813
1384            &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1385        }
1386
1387        /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1388        #[cfg(not(target_os = "freebsd"))]
1389        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1390            &mut self.sigevent
1391        }
1392    }
1393
1394    impl<'a> From<&'a libc::sigevent> for SigEvent {
1395        #[cfg(target_os = "freebsd")]
1396        fn from(sigevent: &libc::sigevent) -> Self {
1397            // Safe because they're really the same structure.  See
1398            // https://github.com/rust-lang/libc/pull/2813
1399            let sigevent = unsafe {
1400                mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1401            };
1402            SigEvent{ sigevent }
1403        }
1404        #[cfg(not(target_os = "freebsd"))]
1405        fn from(sigevent: &libc::sigevent) -> Self {
1406            SigEvent{ sigevent: *sigevent }
1407        }
1408    }
1409    }
1410}