1use unsafe_cell::UnsafeRefCell;
2use ffi::{RawFd, AsRawFd, getnonblock, setnonblock};
3use error::{ErrCode, READY, ECANCELED, EINTR, EAGAIN, last_error, eof};
4use core::{IoContext, AsIoContext, ThreadIoContext, AsyncFd, workplace};
5use async::{Receiver, Handler, WrappedHandler, Operation};
6use reactive_io::{AsAsyncFd, AsyncInput, cancel};
7
8use std::io;
9use std::mem;
10use std::ptr;
11use libc::{self, SFD_CLOEXEC, SIG_SETMASK, c_void, ssize_t, sigset_t, signalfd_siginfo,
12 signalfd, sigemptyset, sigaddset, sigdelset, pthread_sigmask};
13
14#[repr(i32)]
16#[derive(Clone, Eq, PartialEq, Debug)]
17pub enum Signal {
18 SIGHUP = libc::SIGHUP,
20
21 SIGINT = libc::SIGINT,
23
24 SIGQUIT = libc::SIGQUIT,
26
27 SIGILL = libc::SIGILL,
29
30 SIGABRT = libc::SIGABRT,
32
33 SIGFPE = libc::SIGFPE,
35
36 SIGKILL = libc::SIGKILL,
38
39 SIGSEGV = libc::SIGSEGV,
41
42 SIGPIPE = libc::SIGPIPE,
44
45 SIGALRM = libc::SIGALRM,
47
48 SIGTERM = libc::SIGTERM,
50
51 SIGUSR1 = libc::SIGUSR1,
53
54 SIGUSR2 = libc::SIGUSR2,
56
57 SIGCHLD = libc::SIGCHLD,
59
60 SIGCONT = libc::SIGCONT,
62
63 SIGSTOP = libc::SIGSTOP,
65
66 SIGTSTP = libc::SIGTSTP,
68
69 SIGTTIN = libc::SIGTTIN,
71
72 SIGTTOU = libc::SIGTTOU,
74
75 SIGBUS = libc::SIGBUS,
77
78 SIGPOLL = libc::SIGPOLL,
80
81 SIGPROF = libc::SIGPROF,
83
84 SIGSYS = libc::SIGSYS,
86
87 SIGTRAP = libc::SIGTRAP,
89
90 SIGURG = libc::SIGURG,
92
93 SIGVTALRM = libc::SIGVTALRM,
95
96 SIGXCPU = libc::SIGXCPU,
98
99 SIGXFSZ = libc::SIGXFSZ,
101}
102
103pub fn raise(signal: Signal) -> io::Result<()> {
104 libc_try!(libc::raise(signal as i32));
105 Ok(())
106}
107
108fn signalfd_init() -> io::Result<(RawFd, sigset_t)> {
109 let mut mask: sigset_t = unsafe { mem::uninitialized() };
110 libc_ign!(sigemptyset(&mut mask));
111 let sfd = libc_try!(signalfd(-1, &mask, SFD_CLOEXEC));
112 Ok((sfd, mask))
113}
114
115fn signalfd_add(sfd: RawFd, mask: &mut sigset_t, signal: Signal) -> io::Result<()> {
116 libc_try!(sigaddset(mask, signal as i32));
117 libc_ign!(pthread_sigmask(SIG_SETMASK, mask, ptr::null_mut()));
118 libc_ign!(signalfd(sfd, mask, 0));
119 Ok(())
120}
121
122fn signalfd_del(sfd: RawFd, mask: &mut sigset_t, signal: Signal) -> io::Result<()> {
123 libc_try!(sigdelset(mask, signal as i32));
124 libc_ign!(pthread_sigmask(SIG_SETMASK, mask, ptr::null_mut()));
125 libc_ign!(signalfd(sfd, mask, 0));
126 Ok(())
127}
128
129fn signalfd_reset(sfd: RawFd, mask: &mut sigset_t) -> io::Result<()> {
130 libc_try!(sigemptyset(mask));
131 libc_ign!(pthread_sigmask(SIG_SETMASK, mask, ptr::null_mut()));
132 libc_ign!(signalfd(sfd, mask, 0));
133 Ok(())
134}
135
136unsafe fn signalfd_read(sfd: RawFd, ssi: &mut signalfd_siginfo) -> ssize_t
137{
138 libc::read(sfd, ssi as *mut _ as *mut c_void, mem::size_of_val(ssi))
139}
140
141fn signalfd_wait<T>(sfd: &T) -> io::Result<Signal>
142 where T: AsyncInput,
143{
144 while !sfd.as_ctx().stopped() {
145 let mut ssi: signalfd_siginfo = unsafe { mem::uninitialized() };
146 let len = unsafe { signalfd_read(sfd.as_raw_fd(), &mut ssi) };
147 if len > 0 {
148 return Ok(unsafe { mem::transmute(ssi.ssi_signo) });
149 }
150 if len == 0 {
151 return Err(eof());
152 }
153 let ec = last_error();
154 if ec != EINTR {
155 return Err(ec.into());
156 }
157 }
158 Err(ECANCELED.into())
159}
160
161struct SignalHandler<T> {
162 sfd: UnsafeRefCell<T>
163}
164
165impl<T> WrappedHandler<Signal, io::Error> for SignalHandler<T>
166 where T: AsyncInput,
167{
168 fn perform(&mut self, ctx: &IoContext, this: &mut ThreadIoContext, ec: ErrCode, op: Operation<Signal, io::Error, Self>) {
169 let sfd = unsafe { self.sfd.as_ref() };
170 match ec {
171 READY => {
172 let mode = getnonblock(sfd).unwrap();
173 setnonblock(sfd, true).unwrap();
174
175 while !ctx.stopped() {
176 let mut ssi: signalfd_siginfo = unsafe { mem::uninitialized() };
177 let len = unsafe { signalfd_read(sfd.as_raw_fd(), &mut ssi) };
178 if len > 0 {
179 setnonblock(sfd, mode).unwrap();
180 sfd.next_op(this);
181 op.send(ctx, Ok(unsafe { mem::transmute(ssi.ssi_signo) }));
182 return;
183 }
184 if len == 0 {
185 setnonblock(sfd, mode).unwrap();
186 sfd.next_op(this);
187 op.send(ctx, Err(eof()));
188 return;
189 }
190
191 let ec = last_error();
192 if ec == EAGAIN {
193 setnonblock(sfd, mode).unwrap();
194 sfd.add_op(this, op, ec);
195 return;
196 }
197 if ec != EINTR {
198 setnonblock(sfd, mode).unwrap();
199 sfd.next_op(this);
200 op.send(ctx, Err(ec.into()));
201 return;
202 }
203 }
204
205 setnonblock(sfd, mode).unwrap();
206 sfd.next_op(this);
207 op.send(ctx, Err(ECANCELED.into()));
208 return;
209 },
210 ec => op.send(ctx, Err(ec.into())),
211 }
212 }
213}
214
215fn signalfd_async_wait<T, F>(sfd: &T, handler: F) -> F::Output
216 where T: AsyncInput,
217 F: Handler<Signal, io::Error>,
218{
219 let (op, res) = handler.channel(SignalHandler { sfd: UnsafeRefCell::new(sfd) });
220 workplace(sfd.as_ctx(), |this| sfd.add_op(this, op, READY));
221 res.recv(sfd.as_ctx())
222}
223
224pub struct SignalSet {
226 fd: AsyncFd,
227 mask: sigset_t,
228}
229
230impl Drop for SignalSet {
231 fn drop(&mut self) {
232 signalfd_reset(self.fd.as_raw_fd(), &mut self.mask).unwrap();
233 }
234}
235
236impl SignalSet {
237 pub fn new(ctx: &IoContext) -> io::Result<SignalSet> {
238 let (fd, mask) = try!(signalfd_init());
239 Ok(SignalSet {
240 fd: AsyncFd::new::<Self>(fd, ctx),
241 mask: mask,
242 })
243 }
244
245 pub fn add(&mut self, signal: Signal) -> io::Result<()> {
246 signalfd_add(self.as_raw_fd(), &mut self.mask, signal)
247 }
248
249 pub fn async_wait<F>(&self, handler: F) -> F::Output
250 where F: Handler<Signal, io::Error>,
251 {
252 signalfd_async_wait(self, handler)
253 }
254
255 pub fn cancel(&self) -> &Self {
256 cancel(self);
257 self
258 }
259
260 pub fn clear(&mut self) -> io::Result<()> {
261 signalfd_reset(self.as_raw_fd(), &mut self.mask)
262 }
263
264 pub fn remove(&mut self, signal: Signal) -> io::Result<()> {
265 signalfd_del(self.as_raw_fd(), &mut self.mask, signal)
266 }
267
268 pub fn wait(&self) -> io::Result<Signal> {
269 signalfd_wait(self)
270 }
271}
272
273impl AsRawFd for SignalSet {
274 fn as_raw_fd(&self) -> RawFd {
275 self.fd.as_raw_fd()
276 }
277}
278
279unsafe impl Send for SignalSet { }
280
281unsafe impl AsIoContext for SignalSet {
282 fn as_ctx(&self) -> &IoContext {
283 self.fd.as_ctx()
284 }
285}
286
287impl AsAsyncFd for SignalSet {
288 fn as_fd(&self) -> &AsyncFd {
289 &self.fd
290 }
291}
292
293#[test]
294fn test_signal_set() {
295 use core::IoContext;
296
297 let ctx = &IoContext::new().unwrap();
298 let mut sig = SignalSet::new(ctx).unwrap();
299 sig.add(Signal::SIGHUP).unwrap();
300 sig.add(Signal::SIGUSR1).unwrap();
301 sig.remove(Signal::SIGUSR1).unwrap();
302 sig.remove(Signal::SIGUSR2).unwrap();
303}
304
305#[test]
306fn test_signal_set_wait() {
307 use core::IoContext;
308
309 let ctx = &IoContext::new().unwrap();
310 let mut sig = SignalSet::new(ctx).unwrap();
311 sig.add(Signal::SIGHUP).unwrap();
312 sig.add(Signal::SIGUSR1).unwrap();
313 raise(Signal::SIGHUP).unwrap();
314 raise(Signal::SIGUSR1).unwrap();
315 assert_eq!(sig.wait().unwrap(), Signal::SIGHUP);
316 assert_eq!(sig.wait().unwrap(), Signal::SIGUSR1);
317}