use std::thread;
use std::os::unix::io::AsRawFd;
use nix::sys::signalfd::*;
use nix::sys::signal::{SIGINT, SIGTERM};
use error::Result;
use handler::*;
use poll::*;
use super::logging::LoggingBackend;
pub mod simplemux;
pub struct Server<L: LoggingBackend> {
epfd: EpollFd,
sigfd: SignalFd,
_sigfd: u64,
lb: L,
terminated: bool,
}
unsafe impl<L: LoggingBackend + Send> Send for Server<L> {}
impl<L> Server<L>
where L: LoggingBackend + Send
{
pub fn bind<I: ServerImpl + Send + 'static>(im: I, lb: L) -> Result<()> {
trace!("bind()");
let mut mask = SigSet::empty();
mask.add(SIGINT);
mask.add(SIGTERM);
let loop_ms = im.get_loop_ms();
thread::spawn(move || {
try!(mask.thread_block());
im.bind(mask)
});
try!(mask.thread_block());
let sigfd = try!(SignalFd::with_flags(&mask, SFD_NONBLOCK));
let fd = sigfd.as_raw_fd();
let mut epoll = try!(Epoll::new_with(loop_ms, |epfd| {
let log = lb.setup(&epfd).unwrap();
::log::set_logger(|max_log_level| {
max_log_level.set(lb.level().to_log_level_filter());
log
})
.unwrap();
Box::new(Server {
epfd: epfd,
sigfd: sigfd,
_sigfd: fd as u64,
lb: lb,
terminated: false,
})
}));
let siginfo = EpollEvent {
events: EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLRDHUP | EPOLLERR,
data: fd as u64,
};
try!(epoll.epfd.register(fd, &siginfo));
epoll.run()
}
}
impl<L: LoggingBackend> Drop for Server<L> {
fn drop(&mut self) {
}
}
impl<L: LoggingBackend> Handler<EpollEvent> for Server<L> {
fn is_terminated(&self) -> bool {
self.terminated
}
fn ready(&mut self, ev: &EpollEvent) {
trace!("ready(): {:?}: {:?}", ev.data, ev.events);
if ev.data == self._sigfd {
match self.sigfd.read_signal() {
Ok(Some(sig)) => {
warn!("received signal {:?}. Shutting down..", sig.ssi_signo);
self.terminated = true;
}
Ok(None) => debug!("read_signal(): not ready to read"),
Err(err) => error!("read_signal(): {}", err),
}
} else {
self.lb.ready(ev)
}
}
}
pub trait ServerImpl {
fn stop(&mut self);
fn get_loop_ms(&self) -> isize;
fn bind(self, mask: SigSet) -> Result<()>;
}