#[cfg(unix)]
mod imp {
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
static DRAINING: AtomicBool = AtomicBool::new(false);
static FORCE: AtomicBool = AtomicBool::new(false);
static CHILD_EXIT: AtomicBool = AtomicBool::new(false);
static RELOAD: AtomicBool = AtomicBool::new(false);
static RELOAD_FROM_WATCH: AtomicBool = AtomicBool::new(false);
static RELOADING: AtomicBool = AtomicBool::new(false);
static LAME_DUCK: AtomicBool = AtomicBool::new(false);
static PAUSED: AtomicBool = AtomicBool::new(false);
static INTEL_ALL_DOWN: AtomicBool = AtomicBool::new(false);
static WAKE_R: AtomicI32 = AtomicI32::new(-1);
static WAKE_W: AtomicI32 = AtomicI32::new(-1);
fn wake() {
let w = WAKE_W.load(Ordering::Relaxed);
if w >= 0 {
let b = [0u8; 1];
unsafe {
libc::write(w, b.as_ptr() as *const libc::c_void, 1);
}
}
}
extern "C" fn on_term(_sig: libc::c_int) {
if DRAINING.swap(true, Ordering::SeqCst) {
FORCE.store(true, Ordering::SeqCst);
}
wake();
}
extern "C" fn on_chld(_sig: libc::c_int) {
CHILD_EXIT.store(true, Ordering::SeqCst);
wake();
}
#[cfg(feature = "hot-reload")]
extern "C" fn on_hup(_sig: libc::c_int) {
RELOAD.store(true, Ordering::SeqCst);
wake();
}
fn set_handler(sig: libc::c_int, handler: libc::sighandler_t, flags: libc::c_int) {
unsafe {
let mut sa: libc::sigaction = std::mem::zeroed();
sa.sa_sigaction = handler;
libc::sigemptyset(&mut sa.sa_mask);
sa.sa_flags = flags; libc::sigaction(sig, &sa, std::ptr::null_mut());
}
}
fn make_self_pipe() {
if WAKE_R.load(Ordering::SeqCst) >= 0 {
return; }
let mut fds = [0 as libc::c_int; 2];
if unsafe { libc::pipe(fds.as_mut_ptr()) } != 0 {
return;
}
for &fd in &fds {
unsafe {
let fl = libc::fcntl(fd, libc::F_GETFL);
libc::fcntl(fd, libc::F_SETFL, fl | libc::O_NONBLOCK);
let fdfl = libc::fcntl(fd, libc::F_GETFD);
libc::fcntl(fd, libc::F_SETFD, fdfl | libc::FD_CLOEXEC);
}
}
WAKE_R.store(fds[0], Ordering::SeqCst);
WAKE_W.store(fds[1], Ordering::SeqCst);
}
pub fn install() {
make_self_pipe();
let term = on_term as extern "C" fn(libc::c_int) as libc::sighandler_t;
let chld = on_chld as extern "C" fn(libc::c_int) as libc::sighandler_t;
set_handler(libc::SIGTERM, term, 0);
set_handler(libc::SIGINT, term, 0);
set_handler(libc::SIGCHLD, chld, libc::SA_NOCLDSTOP);
set_handler(libc::SIGPIPE, libc::SIG_IGN, 0);
#[cfg(feature = "hot-reload")]
{
let hup = on_hup as extern "C" fn(libc::c_int) as libc::sighandler_t;
set_handler(libc::SIGHUP, hup, 0);
}
}
pub fn draining() -> bool {
DRAINING.load(Ordering::SeqCst)
}
pub fn force() -> bool {
FORCE.load(Ordering::SeqCst)
}
pub fn request_drain() {
DRAINING.store(true, Ordering::SeqCst);
wake();
}
pub fn lame_duck() -> bool {
LAME_DUCK.load(Ordering::SeqCst)
}
pub fn set_lame_duck(on: bool) {
LAME_DUCK.store(on, Ordering::SeqCst);
}
pub fn paused() -> bool {
PAUSED.load(Ordering::SeqCst)
}
pub fn set_paused(on: bool) {
PAUSED.store(on, Ordering::SeqCst);
}
pub fn intel_all_down() -> bool {
INTEL_ALL_DOWN.load(Ordering::SeqCst)
}
pub fn set_intel_all_down(on: bool) -> bool {
INTEL_ALL_DOWN.swap(on, Ordering::SeqCst) != on
}
pub fn take_child_exit() -> bool {
CHILD_EXIT.swap(false, Ordering::SeqCst)
}
pub fn reload_requested() -> bool {
RELOAD.load(Ordering::SeqCst)
}
pub fn clear_reload() {
RELOAD.store(false, Ordering::SeqCst);
}
pub fn request_reload() {
RELOAD.store(true, Ordering::SeqCst);
wake();
}
pub fn request_reload_from_watch() {
RELOAD_FROM_WATCH.store(true, Ordering::SeqCst);
RELOAD.store(true, Ordering::SeqCst);
wake();
}
pub fn take_reload_was_watch() -> bool {
RELOAD_FROM_WATCH.swap(false, Ordering::SeqCst)
}
pub fn reloading() -> bool {
RELOADING.load(Ordering::SeqCst)
}
pub fn set_reloading(on: bool) {
RELOADING.store(on, Ordering::SeqCst);
}
pub fn wakeup_fd() -> i32 {
WAKE_R.load(Ordering::SeqCst)
}
pub fn drain_wakeup() {
let r = WAKE_R.load(Ordering::SeqCst);
if r < 0 {
return;
}
let mut buf = [0u8; 64];
loop {
let n = unsafe { libc::read(r, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) };
if n <= 0 {
break; }
}
}
#[cfg(test)]
pub fn clear_drain_for_test() {
DRAINING.store(false, Ordering::SeqCst);
FORCE.store(false, Ordering::SeqCst);
}
}
#[cfg(not(unix))]
mod imp {
pub fn install() {}
#[cfg(test)]
pub fn clear_drain_for_test() {}
pub fn draining() -> bool {
false
}
pub fn force() -> bool {
false
}
pub fn request_drain() {}
pub fn lame_duck() -> bool {
false
}
pub fn set_lame_duck(_on: bool) {}
pub fn paused() -> bool {
false
}
pub fn set_paused(_on: bool) {}
pub fn intel_all_down() -> bool {
false
}
pub fn set_intel_all_down(_on: bool) -> bool {
false
}
pub fn take_child_exit() -> bool {
false
}
pub fn reload_requested() -> bool {
false
}
pub fn clear_reload() {}
pub fn request_reload() {}
pub fn request_reload_from_watch() {}
pub fn take_reload_was_watch() -> bool {
false
}
pub fn reloading() -> bool {
false
}
pub fn set_reloading(_on: bool) {}
pub fn wakeup_fd() -> i32 {
-1
}
pub fn drain_wakeup() {}
}
pub fn install() {
imp::install();
}
pub fn draining() -> bool {
imp::draining()
}
pub fn force() -> bool {
imp::force()
}
pub fn request_drain() {
imp::request_drain()
}
pub fn lame_duck() -> bool {
imp::lame_duck()
}
pub fn set_lame_duck(on: bool) {
imp::set_lame_duck(on)
}
pub fn paused() -> bool {
imp::paused()
}
pub fn set_paused(on: bool) {
imp::set_paused(on)
}
pub fn intel_all_down() -> bool {
imp::intel_all_down()
}
pub fn set_intel_all_down(on: bool) -> bool {
imp::set_intel_all_down(on)
}
pub fn take_child_exit() -> bool {
imp::take_child_exit()
}
pub fn reload_requested() -> bool {
imp::reload_requested()
}
pub fn clear_reload() {
imp::clear_reload()
}
pub fn request_reload() {
imp::request_reload()
}
pub fn request_reload_from_watch() {
imp::request_reload_from_watch()
}
pub fn take_reload_was_watch() -> bool {
imp::take_reload_was_watch()
}
pub fn reloading() -> bool {
imp::reloading()
}
pub fn set_reloading(on: bool) {
imp::set_reloading(on)
}
pub fn wakeup_fd() -> i32 {
imp::wakeup_fd()
}
pub fn drain_wakeup() {
imp::drain_wakeup()
}
#[cfg(test)]
static SIGNALS_TEST_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[cfg(test)]
pub fn reset_for_test() {
imp::clear_drain_for_test();
set_lame_duck(false);
set_paused(false);
set_reloading(false);
clear_reload();
let _ = set_intel_all_down(false);
let _ = take_reload_was_watch();
}
#[cfg(test)]
pub struct SignalsTestGuard(#[allow(dead_code)] std::sync::MutexGuard<'static, ()>);
#[cfg(test)]
impl Drop for SignalsTestGuard {
fn drop(&mut self) {
reset_for_test();
}
}
#[cfg(test)]
pub fn test_guard() -> SignalsTestGuard {
let g = SIGNALS_TEST_LOCK
.lock()
.unwrap_or_else(|poison| poison.into_inner());
reset_for_test();
SignalsTestGuard(g)
}