1#![cfg_attr(feature="nightly", feature(static_condvar))]
4#![cfg_attr(feature="nightly", feature(static_mutex))]
5
6#[cfg(feature="stable")]
7#[macro_use]
8extern crate lazy_static;
9
10use std::sync::atomic::Ordering;
11use std::thread;
12
13#[derive(Clone, Copy, PartialEq, Eq, Debug)]
14pub enum Signal {
15 Hup,
16 Int,
17 Quit,
18 Ill,
19 Abrt,
20 Fpe,
21 Kill,
22 Segv,
23 Pipe,
24 Alrm,
25 Term,
26}
27
28#[cfg(feature="nightly")]
29mod features {
30 use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
31 use std::sync::{StaticCondvar, CONDVAR_INIT, StaticMutex, MUTEX_INIT};
32 pub static CVAR: StaticCondvar = CONDVAR_INIT;
33 pub static MUTEX: StaticMutex = MUTEX_INIT;
34 pub static MASK: AtomicUsize = ATOMIC_USIZE_INIT;
35}
36
37#[cfg(not(feature="nightly"))]
38mod features {
39 use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
40 use std::sync::{Condvar, Mutex};
41 lazy_static! {
42 pub static ref CVAR: Condvar = Condvar::new();
43 pub static ref MUTEX: Mutex<bool> = Mutex::new(false);
44 }
45 pub static MASK: AtomicUsize = ATOMIC_USIZE_INIT;
46}
47
48use self::features::*;
49
50#[cfg(unix)]
51mod platform {
52 extern crate libc;
53
54 use self::libc::{c_int, signal, sighandler_t};
55 use self::libc::{SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGKILL, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM};
56 use std::mem;
57 use std::sync::atomic::Ordering;
58 use super::Signal;
59
60 pub extern "C" fn handler(sig: c_int) {
61 let mask = match sig {
62 SIGHUP => 1,
63 SIGINT => 2,
64 SIGQUIT => 4,
65 SIGILL => 8,
66 SIGABRT => 16,
67 SIGFPE => 32,
68 SIGKILL => 64,
69 SIGSEGV => 128,
70 SIGPIPE => 256,
71 SIGALRM => 512,
72 SIGTERM => 1024,
73 _ => return,
74 };
75
76 loop {
77 let prev_mask = super::features::MASK.load(Ordering::Relaxed);
78 let new_mask = prev_mask | mask;
79 if super::features::MASK.compare_and_swap(prev_mask, new_mask, Ordering::Relaxed) == new_mask {
80 break;
81 }
82 }
83 super::features::CVAR.notify_all();
84 }
85
86 #[inline]
87 pub unsafe fn set_os_handler(sig: Signal) {
88 let os_sig = match sig {
89 Signal::Hup => SIGHUP,
90 Signal::Int => SIGINT,
91 Signal::Quit => SIGQUIT,
92 Signal::Ill => SIGILL,
93 Signal::Abrt => SIGABRT,
94 Signal::Fpe => SIGFPE,
95 Signal::Kill => SIGKILL,
96 Signal::Segv => SIGSEGV,
97 Signal::Pipe => SIGPIPE,
98 Signal::Alrm => SIGALRM,
99 Signal::Term => SIGTERM,
100 };
101
102 signal(os_sig, mem::transmute::<_, sighandler_t>(handler as extern "C" fn(_)));
103 }
104}
105
106use self::platform::*;
107
108pub fn set_handler<F>(signals: &[Signal], user_handler: F) where F: Fn(&[Signal]) + 'static + Send {
116 for &signal in signals.iter() {
117 unsafe { set_os_handler(signal) }
118 }
119 thread::spawn(move || {
120 let mut signals = Vec::new();
121 loop {
122 let mask = MASK.load(Ordering::Relaxed);
123 if mask == 0 {
124 let _ = CVAR.wait(MUTEX.lock().unwrap());
125 thread::yield_now();
126 continue;
127 }
128 signals.clear();
129 if mask & 1 != 0 { signals.push(Signal::Hup) }
130 if mask & 2 != 0 { signals.push(Signal::Int) }
131 if mask & 4 != 0 { signals.push(Signal::Quit) }
132 if mask & 8 != 0 { signals.push(Signal::Ill) }
133 if mask & 16 != 0 { signals.push(Signal::Abrt) }
134 if mask & 32 != 0 { signals.push(Signal::Fpe) }
135 if mask & 64 != 0 { signals.push(Signal::Kill) }
136 if mask & 128 != 0 { signals.push(Signal::Segv) }
137 if mask & 256 != 0 { signals.push(Signal::Pipe) }
138 if mask & 512 != 0 { signals.push(Signal::Alrm) }
139 if mask & 1024 != 0 { signals.push(Signal::Term) }
140 MASK.store(0, Ordering::Relaxed);
141 user_handler(&signals);
142 }
143 });
144}
145
146#[cfg(test)]
147mod test {
148 extern crate libc;
149
150 use std::sync::mpsc::sync_channel;
151 use self::libc::c_int;
152 use self::libc::{SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGKILL, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM};
153 use super::{Signal};
154 use super::platform::handler;
155
156 fn to_os_signal(signal: Signal) -> c_int {
157 match signal {
158 Signal::Hup => SIGHUP,
159 Signal::Int => SIGINT,
160 Signal::Quit => SIGQUIT,
161 Signal::Ill => SIGILL,
162 Signal::Abrt => SIGABRT,
163 Signal::Fpe => SIGFPE,
164 Signal::Kill => SIGKILL,
165 Signal::Segv => SIGSEGV,
166 Signal::Pipe => SIGPIPE,
167 Signal::Alrm => SIGALRM,
168 Signal::Term => SIGTERM,
169 }
170 }
171
172 #[test]
173 fn all_signals() {
174 let signals = [Signal::Hup, Signal::Int, Signal::Quit, Signal::Abrt, Signal::Term];
175 let (tx, rx) = sync_channel(0);
176 super::set_handler(&signals, move |signals| tx.send(signals.to_owned()).unwrap());
177 for &signal in signals.iter() {
179 handler(to_os_signal(signal));
180 assert_eq!(rx.recv().unwrap(), vec![signal]);
181 }
182 for &signal in signals.iter() {
184 handler(to_os_signal(signal))
185 }
186 assert_eq!(rx.recv().unwrap(), signals.to_owned());
187 }
188}