/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ #[cfg(windows)] use std::{io, ptr}; #[cfg(windows)] use winapi::{ shared::winerror::ERROR_ALREADY_EXISTS, um::{handleapi::CloseHandle, synchapi::CreateMutexA, winnt::HANDLE}, }; use super::errors::CodeError; pub struct AppMutex { #[cfg(windows)] handle: HANDLE, } #[cfg(windows)] // handle is thread-safe, mark it so with this unsafe impl Send for AppMutex {} impl AppMutex { #[cfg(unix)] pub fn new(_name: &str) -> Result { Ok(Self {}) } #[cfg(windows)] pub fn new(name: &str) -> Result { use std::ffi::CString; let cname = CString::new(name).unwrap(); let handle = unsafe { CreateMutexA(ptr::null_mut(), 0, cname.as_ptr() as _) }; if !handle.is_null() { return Ok(Self { handle }); } let err = io::Error::last_os_error(); let raw = err.raw_os_error(); // docs report it should return ERROR_IO_PENDING, but in my testing it actually // returns ERROR_LOCK_VIOLATION. Or maybe winapi is wrong? if raw == Some(ERROR_ALREADY_EXISTS as i32) { return Err(CodeError::AppAlreadyLocked(name.to_string())); } Err(CodeError::AppLockFailed(err)) } } impl Drop for AppMutex { fn drop(&mut self) { #[cfg(windows)] unsafe { CloseHandle(self.handle) }; } }