#![allow(unsafe_code)]
use std::ffi::OsString;
use std::io::Result;
use std::os::windows::ffi::OsStrExt;
use windows_sys::core::PCWSTR;
use windows_sys::Win32::Foundation::{CloseHandle, BOOL, HANDLE, WAIT_OBJECT_0, WAIT_TIMEOUT};
use windows_sys::Win32::System::Threading::{CreateSemaphoreW, ReleaseSemaphore, WaitForSingleObject};
pub const NULL_HANDLE: HANDLE = 0;
pub fn create(initial_count: i32, max_count: i32) -> Result<HANDLE> {
let name: Vec<u16> = OsString::from("Local\\i2pd-launch_Local_AppSemaphore_v1")
.encode_wide()
.chain(Some(0))
.collect();
let handle: HANDLE = unsafe { CreateSemaphoreW(std::ptr::null_mut(), initial_count, max_count, name.as_ptr() as PCWSTR) };
if handle == NULL_HANDLE {
Err(std::io::Error::last_os_error())
} else {
Ok(handle)
}
}
pub fn acquire(handle: HANDLE, timeout_ms: u32) -> Result<HANDLE> {
let result = unsafe { WaitForSingleObject(handle, timeout_ms) };
if result == WAIT_OBJECT_0 {
Ok(handle)
} else if result == WAIT_TIMEOUT {
Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"Timeout waiting for a semaphore",
))
} else {
Err(std::io::Error::last_os_error())
}
}
pub fn release(handle: HANDLE) -> Result<HANDLE> {
let result: BOOL = unsafe { ReleaseSemaphore(handle, 1, std::ptr::null_mut()) };
if result == 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(handle)
}
}
pub fn close(handle: HANDLE) -> Result<()> {
let result: BOOL = unsafe { CloseHandle(handle) };
if result == 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(())
}
}
#[cfg(test)]
#[path = "sem_tests.rs"]
mod sem_tests;