use std::io;
use std::ptr;
use winapi::ctypes::c_long;
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
use winapi::shared::ntdef::HANDLE;
use winapi::um::consoleapi::SetConsoleCtrlHandler;
use winapi::um::handleapi::CloseHandle;
use winapi::um::synchapi::{ReleaseSemaphore, WaitForSingleObject};
use winapi::um::winbase::{CreateSemaphoreA, INFINITE, WAIT_FAILED, WAIT_OBJECT_0};
use std::future::Future;
use crate::error::Error as CtrlcError;
pub type Error = io::Error;
pub type Signal = DWORD;
const MAX_SEM_COUNT: c_long = 255;
static mut SEMAPHORE: HANDLE = 0 as HANDLE;
unsafe extern "system" fn os_handler(_: DWORD) -> BOOL {
ReleaseSemaphore(SEMAPHORE, 1, ptr::null_mut());
TRUE
}
#[inline]
pub unsafe fn init_os_handler() -> Result<impl Future<Output=Result<(), CtrlcError>>, Error>
{
SEMAPHORE = CreateSemaphoreA(ptr::null_mut(), 0, MAX_SEM_COUNT, ptr::null());
if SEMAPHORE.is_null() {
return Err(io::Error::last_os_error());
}
if SetConsoleCtrlHandler(Some(os_handler), TRUE) == FALSE {
let e = io::Error::last_os_error();
CloseHandle(SEMAPHORE);
SEMAPHORE = 0 as HANDLE;
return Err(e);
}
Ok(
async move {
match WaitForSingleObject(SEMAPHORE, INFINITE) {
WAIT_OBJECT_0 => Ok(()),
WAIT_FAILED => Err(CtrlcError::System(io::Error::last_os_error())),
ret => Err(CtrlcError::System(io::Error::new(
io::ErrorKind::Other,
format!(
"WaitForSingleObject(), unexpected return value \"{:x}\"",
ret
),
))),
}
}
)
}