use windows_sys::Win32::Foundation::{CloseHandle, FALSE, HANDLE, TRUE, WAIT_FAILED, WAIT_OBJECT_0};
use windows_sys::Win32::System::Console::{CTRL_BREAK_EVENT, CTRL_C_EVENT, SetConsoleCtrlHandler};
use windows_sys::Win32::System::Threading::{CreateSemaphoreA, INFINITE, ReleaseSemaphore, WaitForSingleObject};
use windows_sys::core::BOOL;
pub type Error = std::io::Error;
pub type Signal = u32;
const MAX_SEM_COUNT: i32 = 255;
static mut SEMAPHORE: HANDLE = 0 as HANDLE;
unsafe extern "system" fn os_handler(ctrl_type: u32) -> BOOL {
match ctrl_type {
CTRL_C_EVENT => {
log::debug!("Ctrl-C event received");
}
CTRL_BREAK_EVENT => {
log::debug!("Ctrl-Break event received");
}
_ => {
log::debug!("Unknown control event received: {ctrl_type}");
}
}
unsafe { ReleaseSemaphore(SEMAPHORE, 1, std::ptr::null_mut()) };
TRUE
}
#[inline]
pub unsafe fn init_os_handler(_overwrite: bool) -> Result<(), Error> {
unsafe { SEMAPHORE = CreateSemaphoreA(std::ptr::null_mut(), 0, MAX_SEM_COUNT, std::ptr::null()) };
if unsafe { SEMAPHORE.is_null() } {
let err = std::io::Error::last_os_error();
log::error!("Failed to create semaphore: {err}");
return Err(err);
}
if unsafe { SetConsoleCtrlHandler(Some(os_handler), TRUE) } == FALSE {
let e = std::io::Error::last_os_error();
unsafe { CloseHandle(SEMAPHORE) };
unsafe { SEMAPHORE = 0 as HANDLE };
log::error!("Failed to set console control handler: {e}");
return Err(e);
}
log::debug!("OS signal handler initialized successfully");
Ok(())
}
#[inline]
pub unsafe fn block_ctrl_c() -> Result<(), Error> {
match unsafe { WaitForSingleObject(SEMAPHORE, INFINITE) } {
WAIT_OBJECT_0 => Ok(()),
WAIT_FAILED => Err(std::io::Error::last_os_error()),
r => Err(std::io::Error::other(format!(
"WaitForSingleObject(), unexpected return value \"{r:x}\""
))),
}
}