1 | //! Interface for the `signalfd` syscall. |
2 | //! |
3 | //! # Signal discarding |
4 | //! When a signal can't be delivered to a process (or thread), it will become a pending signal. |
5 | //! Failure to deliver could happen if the signal is blocked by every thread in the process or if |
6 | //! the signal handler is still handling a previous signal. |
7 | //! |
8 | //! If a signal is sent to a process (or thread) that already has a pending signal of the same |
9 | //! type, it will be discarded. This means that if signals of the same type are received faster than |
10 | //! they are processed, some of those signals will be dropped. Because of this limitation, |
11 | //! `signalfd` in itself cannot be used for reliable communication between processes or threads. |
12 | //! |
13 | //! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending |
14 | //! (ie. not consumed from a signalfd) it will be delivered to the signal handler. |
15 | //! |
16 | //! Please note that signal discarding is not specific to `signalfd`, but also happens with regular |
17 | //! signal handlers. |
18 | use crate::errno::Errno; |
19 | pub use crate::sys::signal::{self, SigSet}; |
20 | use crate::Result; |
21 | pub use libc::signalfd_siginfo as siginfo; |
22 | |
23 | use std::mem; |
24 | use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, OwnedFd, AsFd, BorrowedFd}; |
25 | |
26 | libc_bitflags! { |
27 | pub struct SfdFlags: libc::c_int { |
28 | SFD_NONBLOCK; |
29 | SFD_CLOEXEC; |
30 | } |
31 | } |
32 | |
33 | #[deprecated (since = "0.23.0" , note = "use mem::size_of::<siginfo>() instead" )] |
34 | pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>(); |
35 | |
36 | /// Creates a new file descriptor for reading signals. |
37 | /// |
38 | /// **Important:** please read the module level documentation about signal discarding before using |
39 | /// this function! |
40 | /// |
41 | /// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor. |
42 | /// |
43 | /// A signal must be blocked on every thread in a process, otherwise it won't be visible from |
44 | /// signalfd (the default handler will be invoked instead). |
45 | /// |
46 | /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) |
47 | #[deprecated (since = "0.27.0" , note = "Use SignalFd instead" )] |
48 | pub fn signalfd<F: AsFd>(fd: Option<F>, mask: &SigSet, flags: SfdFlags) -> Result<OwnedFd> { |
49 | _signalfd(fd, mask, flags) |
50 | } |
51 | |
52 | fn _signalfd<F: AsFd>(fd: Option<F>, mask: &SigSet, flags: SfdFlags) -> Result<OwnedFd> { |
53 | let raw_fd: i32 = fd.map_or(default:-1, |x: F|x.as_fd().as_raw_fd()); |
54 | unsafe { |
55 | Errno::result(libc::signalfd( |
56 | raw_fd, |
57 | mask.as_ref(), |
58 | flags.bits(), |
59 | )).map(|raw_fd: i32|FromRawFd::from_raw_fd(raw_fd)) |
60 | } |
61 | } |
62 | |
63 | /// A helper struct for creating, reading and closing a `signalfd` instance. |
64 | /// |
65 | /// **Important:** please read the module level documentation about signal discarding before using |
66 | /// this struct! |
67 | /// |
68 | /// # Examples |
69 | /// |
70 | /// ``` |
71 | /// # use nix::sys::signalfd::*; |
72 | /// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used |
73 | /// let mut mask = SigSet::empty(); |
74 | /// mask.add(signal::SIGUSR1); |
75 | /// mask.thread_block().unwrap(); |
76 | /// |
77 | /// // Signals are queued up on the file descriptor |
78 | /// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); |
79 | /// |
80 | /// match sfd.read_signal() { |
81 | /// // we caught a signal |
82 | /// Ok(Some(sig)) => (), |
83 | /// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set, |
84 | /// // otherwise the read_signal call blocks) |
85 | /// Ok(None) => (), |
86 | /// Err(err) => (), // some error happend |
87 | /// } |
88 | /// ``` |
89 | #[derive (Debug)] |
90 | pub struct SignalFd(OwnedFd); |
91 | |
92 | impl SignalFd { |
93 | pub fn new(mask: &SigSet) -> Result<SignalFd> { |
94 | Self::with_flags(mask, SfdFlags::empty()) |
95 | } |
96 | |
97 | pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> { |
98 | let fd = _signalfd(None::<OwnedFd>, mask, flags)?; |
99 | |
100 | Ok(SignalFd(fd)) |
101 | } |
102 | |
103 | pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { |
104 | _signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop) |
105 | } |
106 | |
107 | pub fn read_signal(&mut self) -> Result<Option<siginfo>> { |
108 | let mut buffer = mem::MaybeUninit::<siginfo>::uninit(); |
109 | |
110 | let size = mem::size_of_val(&buffer); |
111 | let res = Errno::result(unsafe { |
112 | libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size) |
113 | }) |
114 | .map(|r| r as usize); |
115 | match res { |
116 | Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })), |
117 | Ok(_) => unreachable!("partial read on signalfd" ), |
118 | Err(Errno::EAGAIN) => Ok(None), |
119 | Err(error) => Err(error), |
120 | } |
121 | } |
122 | } |
123 | |
124 | impl AsFd for SignalFd { |
125 | fn as_fd(&self) -> BorrowedFd { |
126 | self.0.as_fd() |
127 | } |
128 | } |
129 | impl AsRawFd for SignalFd { |
130 | fn as_raw_fd(&self) -> RawFd { |
131 | self.0.as_raw_fd() |
132 | } |
133 | } |
134 | |
135 | impl Iterator for SignalFd { |
136 | type Item = siginfo; |
137 | |
138 | fn next(&mut self) -> Option<Self::Item> { |
139 | match self.read_signal() { |
140 | Ok(Some(sig: signalfd_siginfo)) => Some(sig), |
141 | Ok(None) | Err(_) => None, |
142 | } |
143 | } |
144 | } |
145 | |
146 | #[cfg (test)] |
147 | mod tests { |
148 | use super::*; |
149 | |
150 | #[test ] |
151 | fn create_signalfd() { |
152 | let mask = SigSet::empty(); |
153 | SignalFd::new(&mask).unwrap(); |
154 | } |
155 | |
156 | #[test ] |
157 | fn create_signalfd_with_opts() { |
158 | let mask = SigSet::empty(); |
159 | SignalFd::with_flags( |
160 | &mask, |
161 | SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, |
162 | ) |
163 | .unwrap(); |
164 | } |
165 | |
166 | #[test ] |
167 | fn read_empty_signalfd() { |
168 | let mask = SigSet::empty(); |
169 | let mut fd = |
170 | SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); |
171 | |
172 | let res = fd.read_signal(); |
173 | assert!(res.unwrap().is_none()); |
174 | } |
175 | } |
176 | |