Skip to main content

nix/sys/
signal.rs

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