use crate::error::Error as CtrlcError;
#[cfg(not(target_vendor = "apple"))]
#[allow(static_mut_refs)] mod implementation {
static mut SEMAPHORE: nix::libc::sem_t = unsafe { std::mem::zeroed() };
const SEM_THREAD_SHARED: nix::libc::c_int = 0;
pub unsafe fn sem_init() {
nix::libc::sem_init(&mut SEMAPHORE as *mut _, SEM_THREAD_SHARED, 0);
}
pub unsafe fn sem_post() {
let _ = nix::libc::sem_post(&mut SEMAPHORE as *mut _);
}
pub unsafe fn sem_wait_forever() {
while nix::libc::sem_wait(&mut SEMAPHORE as *mut _) == -1 {}
}
}
#[cfg(target_vendor = "apple")]
mod implementation {
use dispatch2::{DispatchRetained, DispatchSemaphore, DispatchTime};
static mut SEMAPHORE: Option<DispatchRetained<DispatchSemaphore>> = None;
pub unsafe fn sem_init() {
SEMAPHORE = Some(DispatchSemaphore::new(0));
}
#[allow(static_mut_refs)]
pub unsafe fn sem_post() {
SEMAPHORE.as_deref().unwrap().signal();
}
#[allow(static_mut_refs)]
pub unsafe fn sem_wait_forever() {
SEMAPHORE.as_deref().unwrap().wait(DispatchTime::FOREVER);
}
}
pub type Error = nix::Error;
pub type Signal = nix::sys::signal::Signal;
extern "C" fn os_handler(_: nix::libc::c_int) {
unsafe {
implementation::sem_post();
}
}
#[inline]
pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> {
use nix::sys::signal;
implementation::sem_init();
let handler = signal::SigHandler::Handler(os_handler);
#[cfg(not(target_os = "nto"))]
let new_action = signal::SigAction::new(
handler,
signal::SaFlags::SA_RESTART,
signal::SigSet::empty(),
);
#[cfg(target_os = "nto")]
let new_action =
signal::SigAction::new(handler, signal::SaFlags::empty(), signal::SigSet::empty());
let sigint_old = signal::sigaction(signal::Signal::SIGINT, &new_action)?;
if !overwrite && !matches!(sigint_old.handler(), signal::SigHandler::SigDfl) {
signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
return Err(nix::Error::EEXIST);
}
#[cfg(feature = "termination")]
{
let sigterm_old = match signal::sigaction(signal::Signal::SIGTERM, &new_action) {
Ok(old) => old,
Err(e) => {
signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
return Err(e);
}
};
if !overwrite && !matches!(sigterm_old.handler(), signal::SigHandler::SigDfl) {
signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
return Err(nix::Error::EEXIST);
}
let sighup_old = match signal::sigaction(signal::Signal::SIGHUP, &new_action) {
Ok(old) => old,
Err(e) => {
signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
return Err(e);
}
};
if !overwrite && !matches!(sighup_old.handler(), signal::SigHandler::SigDfl) {
signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
signal::sigaction(signal::Signal::SIGHUP, &sighup_old).unwrap();
return Err(nix::Error::EEXIST);
}
}
Ok(())
}
#[inline]
pub unsafe fn block_ctrl_c() -> Result<(), CtrlcError> {
implementation::sem_wait_forever();
Ok(())
}