use std::io;
use windows::Win32::Foundation::{
CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0, WAIT_TIMEOUT,
};
use windows::Win32::System::Threading::{
CreateMutexW, INFINITE, ReleaseMutex, WaitForSingleObject,
};
use windows::core::HSTRING;
#[derive(Debug)]
pub(crate) struct OsLock {
handle: HANDLE,
}
unsafe impl Send for OsLock {}
unsafe impl Sync for OsLock {}
impl OsLock {
pub(crate) fn open(name: &str) -> io::Result<Self> {
let handle =
unsafe { CreateMutexW(None, false, &HSTRING::from(name)).map_err(io::Error::from)? };
Ok(OsLock { handle })
}
pub(crate) fn lock(&self) -> io::Result<()> {
let rc = unsafe { WaitForSingleObject(self.handle, INFINITE) };
if rc == WAIT_OBJECT_0 || rc == WAIT_ABANDONED {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
pub(crate) fn try_lock(&self) -> io::Result<()> {
let rc = unsafe { WaitForSingleObject(self.handle, 0) };
if rc == WAIT_OBJECT_0 || rc == WAIT_ABANDONED {
Ok(())
} else if rc == WAIT_TIMEOUT {
Err(io::Error::from(io::ErrorKind::WouldBlock))
} else {
Err(io::Error::last_os_error())
}
}
pub(crate) fn unlock(&self) -> io::Result<()> {
unsafe { ReleaseMutex(self.handle).map_err(io::Error::from) }
}
}
impl Drop for OsLock {
fn drop(&mut self) {
unsafe {
let _ = CloseHandle(self.handle);
}
}
}