1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
use mio::{unix::EventedFd, PollOpt, Ready, Token};
use nix::{
	self, sys::{
		signal::Signal::{self, *}, signalfd::{siginfo, SfdFlags, SIGNALFD_SIGINFO_SIZE},
	},
};
use std::{cell::RefCell, os::unix::io::RawFd, rc::Rc};
use Notifiable;

thread_local! {
	static SIGNALFD: RefCell<Option<RawFd>> = RefCell::new(None);
	static HANDLER: RefCell<Option<Rc<Notifiable>>> = RefCell::new(None);
	static SIGINFO: RefCell<Option<siginfo>> = RefCell::new(None);
}

pub fn set_signal_handler(handler: Rc<Notifiable>) {
	if SIGNALFD.with(|x| x.borrow().is_none()) {
		let mut mask = nix::sys::signal::SigSet::empty();
		mask.add(SIGWINCH);
		mask.add(SIGCHLD);
		mask.thread_block().unwrap();
		let flags = SfdFlags::SFD_NONBLOCK | SfdFlags::SFD_CLOEXEC;
		let fd = nix::sys::signalfd::signalfd(-1, &mask, flags).unwrap();
		SIGNALFD.with(|x| *x.borrow_mut() = Some(fd));
		let proxy = SignalNotificationProxy {};
		let token = ::insert_listener(Rc::new(proxy));
		::borrow_poll(|x| {
			x.register(&EventedFd(&fd), Token(token), Ready::readable(), PollOpt::level()).unwrap();
		});
	}
	HANDLER.with(|x| *x.borrow_mut() = Some(handler));
}

pub fn get_signal_name() -> String {
	let signal_number = SIGINFO.with(|x| x.borrow().as_ref().unwrap().ssi_signo);
	let signal = Signal::from_c_int(signal_number as _).unwrap();
	format!("{:?}", signal)
}

struct SignalNotificationProxy {}

impl Notifiable for SignalNotificationProxy {
	fn notify(&self) {
		let mut buf = [0u8; SIGNALFD_SIGINFO_SIZE];
		let fd = SIGNALFD.with(|x| x.borrow().as_ref().unwrap().clone());
		nix::unistd::read(fd, &mut buf).unwrap();

		let siginfo = unsafe { ::std::mem::transmute::<_, nix::sys::signalfd::siginfo>(buf) };
		SIGINFO.with(|x| *x.borrow_mut() = Some(siginfo));
		let handler = HANDLER.with(|x| x.borrow().clone());
		if handler.is_some() {
			handler.unwrap().notify();
		}
	}
}