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_os = "redox")] {
430        type SaFlags_t = libc::c_ulong;
431    } else if #[cfg(target_env = "uclibc")] {
432        type SaFlags_t = libc::c_ulong;
433    } else {
434        type SaFlags_t = libc::c_int;
435    }
436}
437}
438
439#[cfg(feature = "signal")]
440libc_bitflags! {
441    /// Controls the behavior of a [`SigAction`]
442    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
443    pub struct SaFlags: SaFlags_t {
444        /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
445        /// generated only when a child process exits, not when a child process
446        /// stops.
447        SA_NOCLDSTOP;
448        /// When catching a [`Signal::SIGCHLD`] signal, the system will not
449        /// create zombie processes when children of the calling process exit.
450        #[cfg(not(target_os = "hurd"))]
451        SA_NOCLDWAIT;
452        /// Further occurrences of the delivered signal are not masked during
453        /// the execution of the handler.
454        SA_NODEFER;
455        /// The system will deliver the signal to the process on a signal stack,
456        /// specified by each thread with sigaltstack(2).
457        SA_ONSTACK;
458        /// The handler is reset back to the default at the moment the signal is
459        /// delivered.
460        SA_RESETHAND;
461        /// Requests that certain system calls restart if interrupted by this
462        /// signal.  See the man page for complete details.
463        SA_RESTART;
464        /// This flag is controlled internally by Nix.
465        SA_SIGINFO;
466    }
467}
468
469#[cfg(feature = "signal")]
470libc_enum! {
471    /// Specifies how certain functions should manipulate a signal mask
472    #[repr(i32)]
473    #[non_exhaustive]
474    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
475    pub enum SigmaskHow {
476        /// The new mask is the union of the current mask and the specified set.
477        SIG_BLOCK,
478        /// The new mask is the intersection of the current mask and the
479        /// complement of the specified set.
480        SIG_UNBLOCK,
481        /// The current mask is replaced by the specified set.
482        SIG_SETMASK,
483    }
484}
485
486feature! {
487#![feature = "signal"]
488
489use crate::unistd::Pid;
490use std::iter::Extend;
491use std::iter::FromIterator;
492use std::iter::IntoIterator;
493
494/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
495// We are using `transparent` here to be super sure that `SigSet`
496// is represented exactly like the `sigset_t` struct from C.
497#[repr(transparent)]
498#[derive(Clone, Copy, Debug, Eq)]
499pub struct SigSet {
500    sigset: libc::sigset_t
501}
502
503impl SigSet {
504    /// Initialize to include all signals.
505    #[doc(alias("sigfillset"))]
506    pub fn all() -> SigSet {
507        let mut sigset = mem::MaybeUninit::uninit();
508        let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
509
510        unsafe{ SigSet { sigset: sigset.assume_init() } }
511    }
512
513    /// Initialize to include nothing.
514    #[doc(alias("sigemptyset"))]
515    pub fn empty() -> SigSet {
516        let mut sigset = mem::MaybeUninit::uninit();
517        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
518
519        unsafe{ SigSet { sigset: sigset.assume_init() } }
520    }
521
522    /// Add the specified signal to the set.
523    #[doc(alias("sigaddset"))]
524    pub fn add(&mut self, signal: Signal) {
525        unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
526    }
527
528    /// Remove all signals from this set.
529    #[doc(alias("sigemptyset"))]
530    pub fn clear(&mut self) {
531        unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
532    }
533
534    /// Remove the specified signal from this set.
535    #[doc(alias("sigdelset"))]
536    pub fn remove(&mut self, signal: Signal) {
537        unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
538    }
539
540    /// Return whether this set includes the specified signal.
541    #[doc(alias("sigismember"))]
542    pub fn contains(&self, signal: Signal) -> bool {
543        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
544
545        match res {
546            1 => true,
547            0 => false,
548            _ => unreachable!("unexpected value from sigismember"),
549        }
550    }
551
552    /// Returns an iterator that yields the signals contained in this set.
553    pub fn iter(&self) -> SigSetIter<'_> {
554        self.into_iter()
555    }
556
557    /// Gets the currently blocked (masked) set of signals for the calling thread.
558    pub fn thread_get_mask() -> Result<SigSet> {
559        let mut oldmask = mem::MaybeUninit::uninit();
560        do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
561        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
562    }
563
564    /// Sets the set of signals as the signal mask for the calling thread.
565    pub fn thread_set_mask(&self) -> Result<()> {
566        pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
567    }
568
569    /// Adds the set of signals to the signal mask for the calling thread.
570    pub fn thread_block(&self) -> Result<()> {
571        pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
572    }
573
574    /// Removes the set of signals from the signal mask for the calling thread.
575    pub fn thread_unblock(&self) -> Result<()> {
576        pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
577    }
578
579    /// Sets the set of signals as the signal mask, and returns the old mask.
580    pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
581        let mut oldmask = mem::MaybeUninit::uninit();
582        do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
583        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
584    }
585
586    /// Suspends execution of the calling thread until one of the signals in the
587    /// signal mask becomes pending, and returns the accepted signal.
588    #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
589    pub fn wait(&self) -> Result<Signal> {
590        use std::convert::TryFrom;
591
592        let mut signum = mem::MaybeUninit::uninit();
593        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
594
595        Errno::result(res).map(|_| unsafe {
596            Signal::try_from(signum.assume_init()).unwrap()
597        })
598    }
599
600    /// Wait for a signal
601    ///
602    /// # Return value
603    /// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`.
604    /// If `sigsuspend(2)` set other error, this function returns `Err`.
605    ///
606    /// For more information see the
607    /// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html).
608    #[cfg(any(
609        bsd,
610        linux_android,
611        solarish,
612        target_os = "haiku",
613        target_os = "hurd",
614        target_os = "aix",
615        target_os = "fuchsia"
616    ))]
617    #[doc(alias("sigsuspend"))]
618    pub fn suspend(&self) -> Result<()> {
619        let res = unsafe {
620            libc::sigsuspend(&self.sigset as *const libc::sigset_t)
621        };
622        match Errno::result(res).map(drop) {
623            Err(Errno::EINTR) => Ok(()),
624            Err(e) => Err(e),
625            Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
626        }
627    }
628
629    /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking  whether the
630    /// `libc::sigset_t` is already initialized.
631    ///
632    /// # Safety
633    ///
634    /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either
635    /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or
636    /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html).
637    /// Otherwise, the results are undefined.
638    pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
639        SigSet { sigset }
640    }
641}
642
643impl From<Signal> for SigSet {
644    fn from(signal: Signal) -> SigSet {
645        let mut sigset = SigSet::empty();
646        sigset.add(signal);
647        sigset
648    }
649}
650
651impl BitOr for Signal {
652    type Output = SigSet;
653
654    fn bitor(self, rhs: Self) -> Self::Output {
655        let mut sigset = SigSet::empty();
656        sigset.add(self);
657        sigset.add(rhs);
658        sigset
659    }
660}
661
662impl BitOr<Signal> for SigSet {
663    type Output = SigSet;
664
665    fn bitor(mut self, rhs: Signal) -> Self::Output {
666        self.add(rhs);
667        self
668    }
669}
670
671impl BitOr for SigSet {
672    type Output = Self;
673
674    fn bitor(self, rhs: Self) -> Self::Output {
675        self.iter().chain(rhs.iter()).collect()
676    }
677}
678
679impl AsRef<libc::sigset_t> for SigSet {
680    fn as_ref(&self) -> &libc::sigset_t {
681        &self.sigset
682    }
683}
684
685// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available.
686impl Extend<Signal> for SigSet {
687    fn extend<T>(&mut self, iter: T)
688    where T: IntoIterator<Item = Signal> {
689        for signal in iter {
690            self.add(signal);
691        }
692    }
693}
694
695impl FromIterator<Signal> for SigSet {
696    fn from_iter<T>(iter: T) -> Self
697    where T: IntoIterator<Item = Signal> {
698        let mut sigset = SigSet::empty();
699        sigset.extend(iter);
700        sigset
701    }
702}
703
704impl PartialEq for SigSet {
705    fn eq(&self, other: &Self) -> bool {
706        for signal in Signal::iterator() {
707            if self.contains(signal) != other.contains(signal) {
708                return false;
709            }
710        }
711        true
712    }
713}
714
715impl Hash for SigSet {
716    fn hash<H: Hasher>(&self, state: &mut H) {
717        for signal in Signal::iterator() {
718            if self.contains(signal) {
719                signal.hash(state);
720            }
721        }
722    }
723}
724
725/// Iterator for a [`SigSet`].
726///
727/// Call [`SigSet::iter`] to create an iterator.
728#[derive(Clone, Debug)]
729pub struct SigSetIter<'a> {
730    sigset: &'a SigSet,
731    inner: SignalIterator,
732}
733
734impl Iterator for SigSetIter<'_> {
735    type Item = Signal;
736    fn next(&mut self) -> Option<Signal> {
737        loop {
738            match self.inner.next() {
739                None => return None,
740                Some(signal) if self.sigset.contains(signal) => return Some(signal),
741                Some(_signal) => continue,
742            }
743        }
744    }
745}
746
747impl<'a> IntoIterator for &'a SigSet {
748    type Item = Signal;
749    type IntoIter = SigSetIter<'a>;
750    fn into_iter(self) -> Self::IntoIter {
751        SigSetIter { sigset: self, inner: Signal::iterator() }
752    }
753}
754
755/// A signal handler.
756#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
757pub enum SigHandler {
758    /// Default signal handling.
759    SigDfl,
760    /// Request that the signal be ignored.
761    SigIgn,
762    /// Use the given signal-catching function, which takes in the signal.
763    Handler(extern "C" fn(libc::c_int)),
764    /// Use the given signal-catching function, which takes in the signal, information about how
765    /// the signal was generated, and a pointer to the threads `ucontext_t`.
766    #[cfg(not(target_os = "redox"))]
767    SigAction(extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
768}
769
770/// Action to take on receipt of a signal. Corresponds to `sigaction`.
771#[repr(transparent)]
772#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
773pub struct SigAction {
774    sigaction: libc::sigaction
775}
776
777impl From<SigAction> for libc::sigaction {
778    fn from(value: SigAction) -> libc::sigaction {
779        value.sigaction
780    }
781}
782
783impl SigAction {
784    /// Creates a new action.
785    ///
786    /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
787    /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
788    /// the signal-catching function.
789    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
790        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
791            unsafe {
792                 (*p).sa_sigaction = match handler {
793                    SigHandler::SigDfl => libc::SIG_DFL,
794                    SigHandler::SigIgn => libc::SIG_IGN,
795                    SigHandler::Handler(f) => f as *const extern "C" fn(libc::c_int) as usize,
796                    #[cfg(not(target_os = "redox"))]
797                    SigHandler::SigAction(f) => f as *const extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
798                };
799            }
800        }
801
802        let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
803        unsafe {
804            let p = s.as_mut_ptr();
805            install_sig(p, handler);
806            (*p).sa_flags = match handler {
807                #[cfg(not(target_os = "redox"))]
808                SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
809                _ => (flags - SaFlags::SA_SIGINFO).bits(),
810            };
811            (*p).sa_mask = mask.sigset;
812
813            SigAction { sigaction: s.assume_init() }
814        }
815    }
816
817    /// Returns the flags set on the action.
818    pub fn flags(&self) -> SaFlags {
819        SaFlags::from_bits_truncate(self.sigaction.sa_flags)
820    }
821
822    /// Returns the set of signals that are blocked during execution of the action's
823    /// signal-catching function.
824    pub fn mask(&self) -> SigSet {
825        SigSet { sigset: self.sigaction.sa_mask }
826    }
827
828    /// Returns the action's handler.
829    pub fn handler(&self) -> SigHandler {
830        match self.sigaction.sa_sigaction {
831            libc::SIG_DFL => SigHandler::SigDfl,
832            libc::SIG_IGN => SigHandler::SigIgn,
833            #[cfg(not(target_os = "redox"))]
834            p if self.flags().contains(SaFlags::SA_SIGINFO) =>
835                SigHandler::SigAction(
836                // Safe for one of two reasons:
837                // * The SigHandler was created by SigHandler::new, in which
838                //   case the pointer is correct, or
839                // * The SigHandler was created by signal or sigaction, which
840                //   are unsafe functions, so the caller should've somehow
841                //   ensured that it is correctly initialized.
842                unsafe{
843                    *(&p as *const usize
844                         as *const extern "C" fn(_, _, _))
845                }
846                as extern "C" fn(_, _, _)),
847            p => SigHandler::Handler(
848                // Safe for one of two reasons:
849                // * The SigHandler was created by SigHandler::new, in which
850                //   case the pointer is correct, or
851                // * The SigHandler was created by signal or sigaction, which
852                //   are unsafe functions, so the caller should've somehow
853                //   ensured that it is correctly initialized.
854                unsafe{
855                    *(&p as *const usize
856                         as *const extern "C" fn(libc::c_int))
857                }
858                as extern "C" fn(libc::c_int)),
859        }
860    }
861}
862
863/// Changes the action taken by a process on receipt of a specific signal.
864///
865/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
866/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
867///
868/// # Safety
869///
870/// * Signal handlers may be called at any point during execution, which limits
871///   what is safe to do in the body of the signal-catching function. Be certain
872///   to only make syscalls that are explicitly marked safe for signal handlers
873///   and only share global data using atomics.
874///
875/// * There is also no guarantee that the old signal handler was installed
876///   correctly.  If it was installed by this crate, it will be.  But if it was
877///   installed by, for example, C code, then there is no guarantee its function
878///   pointer is valid.  In that case, this function effectively dereferences a
879///   raw pointer of unknown provenance.
880pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
881    let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
882
883    let res = unsafe { libc::sigaction(signal as libc::c_int,
884                              &sigaction.sigaction as *const libc::sigaction,
885                              oldact.as_mut_ptr()) };
886
887    Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } })
888}
889
890/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
891///
892/// Installs `handler` for the given `signal`, returning the previous signal
893/// handler. `signal` should only be used following another call to `signal` or
894/// if the current handler is the default. The return value of `signal` is
895/// undefined after setting the handler with [`sigaction`][SigActionFn].
896///
897/// # Safety
898///
899/// If the pointer to the previous signal handler is invalid, undefined
900/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
901///
902/// # Examples
903///
904/// Ignore `SIGINT`:
905///
906/// ```no_run
907/// # use nix::sys::signal::{self, Signal, SigHandler};
908/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
909/// ```
910///
911/// Use a signal handler to set a flag variable:
912///
913/// ```no_run
914/// # use std::convert::TryFrom;
915/// # use std::sync::atomic::{AtomicBool, Ordering};
916/// # use nix::sys::signal::{self, Signal, SigHandler};
917/// static SIGNALED: AtomicBool = AtomicBool::new(false);
918///
919/// extern "C" fn handle_sigint(signal: libc::c_int) {
920///     let signal = Signal::try_from(signal).unwrap();
921///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
922/// }
923///
924/// fn main() {
925///     let handler = SigHandler::Handler(handle_sigint);
926///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
927/// }
928/// ```
929///
930/// # Errors
931///
932/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
933/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
934///
935/// `signal` also returns any error from `libc::signal`, such as when an attempt
936/// is made to catch a signal that cannot be caught or to ignore a signal that
937/// cannot be ignored.
938///
939/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
940/// [SigActionStruct]: struct.SigAction.html
941/// [sigactionFn]: fn.sigaction.html
942pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
943    let signal = signal as libc::c_int;
944    let res = match handler {
945        SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) },
946        SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) },
947        SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) },
948        #[cfg(not(target_os = "redox"))]
949        SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
950    };
951    Errno::result(res).map(|oldhandler| {
952        match oldhandler {
953            libc::SIG_DFL => SigHandler::SigDfl,
954            libc::SIG_IGN => SigHandler::SigIgn,
955            p => SigHandler::Handler(
956                unsafe { *(&p as *const usize as *const extern "C" fn(libc::c_int)) } as extern "C" fn(libc::c_int)),
957        }
958    })
959}
960
961fn do_pthread_sigmask(how: SigmaskHow,
962                       set: Option<&SigSet>,
963                       oldset: Option<*mut libc::sigset_t>) -> Result<()> {
964    if set.is_none() && oldset.is_none() {
965        return Ok(())
966    }
967
968    let res = unsafe {
969        // if set or oldset is None, pass in null pointers instead
970        libc::pthread_sigmask(how as libc::c_int,
971                             set.map_or_else(ptr::null::<libc::sigset_t>,
972                                             |s| &s.sigset as *const libc::sigset_t),
973                             oldset.unwrap_or(ptr::null_mut())
974                             )
975    };
976
977    Errno::result(res).map(drop)
978}
979
980/// Manages the signal mask (set of blocked signals) for the calling thread.
981///
982/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
983/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
984/// and no modification will take place.
985///
986/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
987///
988/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
989/// and then it will be updated with `set`.
990///
991/// If both `set` and `oldset` is None, this function is a no-op.
992///
993/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
994/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
995pub fn pthread_sigmask(how: SigmaskHow,
996                       set: Option<&SigSet>,
997                       oldset: Option<&mut SigSet>) -> Result<()>
998{
999    do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
1000}
1001
1002/// Examine and change blocked signals.
1003///
1004/// For more information see the [`sigprocmask` man
1005/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
1006pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
1007    if set.is_none() && oldset.is_none() {
1008        return Ok(())
1009    }
1010
1011    let res = unsafe {
1012        // if set or oldset is None, pass in null pointers instead
1013        libc::sigprocmask(how as libc::c_int,
1014                          set.map_or_else(ptr::null::<libc::sigset_t>,
1015                                          |s| &s.sigset as *const libc::sigset_t),
1016                          oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
1017                                             |os| &mut os.sigset as *mut libc::sigset_t))
1018    };
1019
1020    Errno::result(res).map(drop)
1021}
1022
1023/// Send a signal to a process
1024///
1025/// # Arguments
1026///
1027/// * `pid` -    Specifies which processes should receive the signal.
1028///   - If positive, specifies an individual process.
1029///   - If zero, the signal will be sent to all processes whose group
1030///     ID is equal to the process group ID of the sender.  This is a
1031#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
1032#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
1033///   - If `-1` and the process has super-user privileges, the signal
1034///     is sent to all processes exclusing system processes.
1035///   - If less than `-1`, the signal is sent to all processes whose
1036///     process group ID is equal to the absolute value of `pid`.
1037/// * `signal` - Signal to send. If `None`, error checking is performed
1038///              but no signal is actually sent.
1039///
1040/// See Also
1041/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
1042pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
1043    let res = unsafe { libc::kill(pid.into(),
1044                                  match signal.into() {
1045                                      Some(s) => s as libc::c_int,
1046                                      None => 0,
1047                                  }) };
1048
1049    Errno::result(res).map(drop)
1050}
1051
1052/// Send a signal to a process group
1053///
1054/// # Arguments
1055///
1056/// * `pgrp` -   Process group to signal.  If less then or equal 1, the behavior
1057///              is platform-specific.
1058/// * `signal` - Signal to send. If `None`, `killpg` will only preform error
1059///              checking and won't send any signal.
1060///
1061/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
1062#[cfg(not(target_os = "fuchsia"))]
1063pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
1064    let res = unsafe { libc::killpg(pgrp.into(),
1065                                  match signal.into() {
1066                                      Some(s) => s as libc::c_int,
1067                                      None => 0,
1068                                  }) };
1069
1070    Errno::result(res).map(drop)
1071}
1072
1073/// Send a signal to the current thread
1074///
1075/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
1076pub fn raise(signal: Signal) -> Result<()> {
1077    let res = unsafe { libc::raise(signal as libc::c_int) };
1078
1079    Errno::result(res).map(drop)
1080}
1081}
1082
1083feature! {
1084#![any(feature = "aio", feature = "signal")]
1085
1086/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1087#[cfg(target_os = "freebsd")]
1088pub type type_of_thread_id = libc::lwpid_t;
1089/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1090#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))]
1091pub type type_of_thread_id = libc::pid_t;
1092
1093/// Specifies the notification method used by a [`SigEvent`]
1094// sigval is actually a union of a int and a void*.  But it's never really used
1095// as a pointer, because neither libc nor the kernel ever dereference it.  nix
1096// therefore presents it as an intptr_t, which is how kevent uses it.
1097#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))]
1098#[derive(Clone, Copy, Debug)]
1099pub enum SigevNotify<'fd> {
1100    /// No notification will be delivered
1101    SigevNone,
1102    /// Notify by delivering a signal to the process.
1103    SigevSignal {
1104        /// Signal to deliver
1105        signal: Signal,
1106        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1107        /// structure of the queued signal.
1108        si_value: libc::intptr_t
1109    },
1110    // Note: SIGEV_THREAD is not implemented, but could be if desired.
1111    /// Notify by delivering an event to a kqueue.
1112    #[cfg(freebsdlike)]
1113    SigevKevent {
1114        /// File descriptor of the kqueue to notify.
1115        kq: std::os::fd::BorrowedFd<'fd>,
1116        /// Will be contained in the kevent's `udata` field.
1117        udata: libc::intptr_t
1118    },
1119    /// Notify by delivering an event to a kqueue, with optional event flags set
1120    #[cfg(target_os = "freebsd")]
1121    #[cfg(feature = "event")]
1122    SigevKeventFlags {
1123        /// File descriptor of the kqueue to notify.
1124        kq: std::os::fd::BorrowedFd<'fd>,
1125        /// Will be contained in the kevent's `udata` field.
1126        udata: libc::intptr_t,
1127        /// Flags that will be set on the delivered event.  See `kevent(2)`.
1128        flags: crate::sys::event::EvFlags
1129    },
1130    /// Notify by delivering a signal to a thread.
1131    #[cfg(any(
1132            target_os = "freebsd",
1133            target_env = "gnu",
1134            target_env = "uclibc",
1135    ))]
1136    SigevThreadId {
1137        /// Signal to send
1138        signal: Signal,
1139        /// LWP ID of the thread to notify
1140        thread_id: type_of_thread_id,
1141        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1142        /// structure of the queued signal.
1143        si_value: libc::intptr_t
1144    },
1145    /// A helper variant to resolve the unused parameter (`'fd`) problem on
1146    /// platforms other than FreeBSD and DragonFlyBSD.
1147    ///
1148    /// This variant can never be constructed due to the usage of an enum with 0
1149    /// variants.
1150    #[doc(hidden)]
1151    #[cfg(not(freebsdlike))]
1152    _Unreachable(&'fd std::convert::Infallible),
1153}
1154}
1155
1156#[cfg(not(any(
1157    target_os = "fuchsia",
1158    target_os = "hurd",
1159    target_os = "openbsd",
1160    target_os = "redox"
1161)))]
1162mod sigevent {
1163    feature! {
1164    #![any(feature = "aio", feature = "signal")]
1165
1166    use std::mem;
1167    use super::SigevNotify;
1168
1169    #[cfg(target_os = "freebsd")]
1170    pub(crate) use ffi::sigevent as libc_sigevent;
1171    #[cfg(not(target_os = "freebsd"))]
1172    pub(crate) use libc::sigevent as libc_sigevent;
1173
1174    // For FreeBSD only, we define the C structure here.  Because the structure
1175    // defined in libc isn't correct.  The real sigevent contains union fields,
1176    // but libc could not represent those when sigevent was originally added, so
1177    // instead libc simply defined the most useful field.  Now that Rust can
1178    // represent unions, there's a PR to libc to fix it.  However, it's stuck
1179    // forever due to backwards compatibility concerns.  Even though there's a
1180    // workaround, libc refuses to merge it.  I think it's just too complicated
1181    // for them to want to think about right now, because that project is
1182    // short-staffed.  So we define it here instead, so we won't have to wait on
1183    // libc.
1184    // https://github.com/rust-lang/libc/pull/2813
1185    #[cfg(target_os = "freebsd")]
1186    mod ffi {
1187        use std::{fmt, hash};
1188
1189        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1190        #[repr(C)]
1191        pub struct __c_anonymous_sigev_thread {
1192            pub _function: *mut libc::c_void,   // Actually a function pointer
1193            pub _attribute: *mut libc::pthread_attr_t,
1194        }
1195        #[derive(Clone, Copy)]
1196        // This will never be used on its own, and its parent has a Debug impl,
1197        // so it doesn't need one.
1198        #[allow(missing_debug_implementations)]
1199        #[repr(C)]
1200        pub union __c_anonymous_sigev_un {
1201            pub _threadid: libc::__lwpid_t,
1202            pub _sigev_thread: __c_anonymous_sigev_thread,
1203            pub _kevent_flags: libc::c_ushort,
1204            __spare__: [libc::c_long; 8],
1205        }
1206
1207        #[derive(Clone, Copy)]
1208        #[repr(C)]
1209        pub struct sigevent {
1210            pub sigev_notify: libc::c_int,
1211            pub sigev_signo: libc::c_int,
1212            pub sigev_value: libc::sigval,
1213            pub _sigev_un: __c_anonymous_sigev_un,
1214        }
1215
1216        impl fmt::Debug for sigevent {
1217            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1218                let mut ds = f.debug_struct("sigevent");
1219                ds.field("sigev_notify", &self.sigev_notify)
1220                    .field("sigev_signo", &self.sigev_signo)
1221                    .field("sigev_value", &self.sigev_value);
1222                // Safe because we check the sigev_notify discriminant
1223                unsafe {
1224                    match self.sigev_notify {
1225                        libc::SIGEV_KEVENT => {
1226                            ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1227                        }
1228                        libc::SIGEV_THREAD_ID => {
1229                            ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1230                        }
1231                        libc::SIGEV_THREAD => {
1232                            ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1233                            ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1234                        }
1235                        _ => ()
1236                    };
1237                }
1238                ds.finish()
1239            }
1240        }
1241
1242        impl PartialEq for sigevent {
1243            fn eq(&self, other: &Self) -> bool {
1244                let mut equals = self.sigev_notify == other.sigev_notify;
1245                equals &= self.sigev_signo == other.sigev_signo;
1246                equals &= self.sigev_value == other.sigev_value;
1247                // Safe because we check the sigev_notify discriminant
1248                unsafe {
1249                    match self.sigev_notify {
1250                        libc::SIGEV_KEVENT => {
1251                            equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1252                        }
1253                        libc::SIGEV_THREAD_ID => {
1254                            equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1255                        }
1256                        libc::SIGEV_THREAD => {
1257                            equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1258                        }
1259                        _ => /* The union field is don't care */ ()
1260                    }
1261                }
1262                equals
1263            }
1264        }
1265
1266        impl Eq for sigevent {}
1267
1268        impl hash::Hash for sigevent {
1269            fn hash<H: hash::Hasher>(&self, s: &mut H) {
1270                self.sigev_notify.hash(s);
1271                self.sigev_signo.hash(s);
1272                self.sigev_value.hash(s);
1273                // Safe because we check the sigev_notify discriminant
1274                unsafe {
1275                    match self.sigev_notify {
1276                        libc::SIGEV_KEVENT => {
1277                            self._sigev_un._kevent_flags.hash(s);
1278                        }
1279                        libc::SIGEV_THREAD_ID => {
1280                            self._sigev_un._threadid.hash(s);
1281                        }
1282                        libc::SIGEV_THREAD => {
1283                            self._sigev_un._sigev_thread.hash(s);
1284                        }
1285                        _ => /* The union field is don't care */ ()
1286                    }
1287                }
1288            }
1289        }
1290    }
1291
1292    /// Used to request asynchronous notification of the completion of certain
1293    /// events, such as POSIX AIO and timers.
1294    #[repr(C)]
1295    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1296    // It can't be Copy on all platforms.
1297    #[allow(missing_copy_implementations)]
1298    pub struct SigEvent {
1299        sigevent: libc_sigevent
1300    }
1301
1302    impl SigEvent {
1303        /// **Note:** this constructor does not allow the user to set the
1304        /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
1305        /// at least those flags don't do anything useful.  That field is part of a
1306        /// union that shares space with the more genuinely useful fields.
1307        ///
1308        /// **Note:** This constructor also doesn't allow the caller to set the
1309        /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
1310        /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
1311        /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
1312        /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
1313        /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
1314        /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
1315        /// more genuinely useful `sigev_notify_thread_id`
1316        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1317            let mut sev: libc_sigevent = unsafe { mem::zeroed() };
1318            match sigev_notify {
1319                SigevNotify::SigevNone => {
1320                    sev.sigev_notify = libc::SIGEV_NONE;
1321                },
1322                SigevNotify::SigevSignal{signal, si_value} => {
1323                    sev.sigev_notify = libc::SIGEV_SIGNAL;
1324                    sev.sigev_signo = signal as libc::c_int;
1325                    sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
1326                },
1327                #[cfg(freebsdlike)]
1328                SigevNotify::SigevKevent{kq, udata} => {
1329                    use std::os::fd::AsRawFd;
1330
1331                    sev.sigev_notify = libc::SIGEV_KEVENT;
1332                    sev.sigev_signo = kq.as_raw_fd();
1333                    sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1334                },
1335                #[cfg(target_os = "freebsd")]
1336                #[cfg(feature = "event")]
1337                SigevNotify::SigevKeventFlags{kq, udata, flags} => {
1338                    use std::os::fd::AsRawFd;
1339
1340                    sev.sigev_notify = libc::SIGEV_KEVENT;
1341                    sev.sigev_signo = kq.as_raw_fd();
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                #[cfg(not(freebsdlike))]
1360                SigevNotify::_Unreachable(_) => unreachable!("This variant could never be constructed")
1361            }
1362            SigEvent{sigevent: sev}
1363        }
1364
1365        /// Return a copy of the inner structure
1366        #[cfg(target_os = "freebsd")]
1367        pub fn sigevent(&self) -> libc::sigevent {
1368            // Safe because they're really the same structure.  See
1369            // https://github.com/rust-lang/libc/pull/2813
1370            unsafe {
1371                mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
1372            }
1373        }
1374
1375        /// Return a copy of the inner structure
1376        #[cfg(not(target_os = "freebsd"))]
1377        pub fn sigevent(&self) -> libc::sigevent {
1378            self.sigevent
1379        }
1380
1381        /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1382        #[cfg(target_os = "freebsd")]
1383        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1384            // Safe because they're really the same structure.  See
1385            // https://github.com/rust-lang/libc/pull/2813
1386            &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1387        }
1388
1389        /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1390        #[cfg(not(target_os = "freebsd"))]
1391        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1392            &mut self.sigevent
1393        }
1394    }
1395
1396    impl From<&'_ libc::sigevent> for SigEvent {
1397        #[cfg(target_os = "freebsd")]
1398        fn from(sigevent: &libc::sigevent) -> Self {
1399            // Safe because they're really the same structure.  See
1400            // https://github.com/rust-lang/libc/pull/2813
1401            let sigevent = unsafe {
1402                mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1403            };
1404            SigEvent{ sigevent }
1405        }
1406        #[cfg(not(target_os = "freebsd"))]
1407        fn from(sigevent: &libc::sigevent) -> Self {
1408            SigEvent{ sigevent: *sigevent }
1409        }
1410    }
1411    }
1412}