Path: blob/main/base/src/sys/windows/multi_process_mutex.rs
5394 views
// Copyright 2022 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::ptr::null_mut;56use serde::Deserialize;7use serde::Serialize;8use winapi::shared::winerror::WAIT_TIMEOUT;9use winapi::um::handleapi::INVALID_HANDLE_VALUE;10use winapi::um::synchapi::CreateMutexA;11use winapi::um::synchapi::ReleaseMutex;12use winapi::um::synchapi::WaitForSingleObject;13use winapi::um::winbase::INFINITE;14use winapi::um::winbase::WAIT_ABANDONED;15use winapi::um::winbase::WAIT_OBJECT_0;1617use super::Error;18use super::Result;19use crate::descriptor::AsRawDescriptor;20use crate::descriptor::FromRawDescriptor;21use crate::descriptor::SafeDescriptor;2223/// A Mutex (no data) that works across processes on Windows.24#[derive(Serialize, Deserialize, Debug)]25pub struct MultiProcessMutex {26lock: SafeDescriptor,27}2829impl MultiProcessMutex {30pub fn new() -> Result<Self> {31// SAFETY: Trivially safe (no memory passed, error checked).32//33// Note that we intentionally make this handle uninheritable by default via the mutex attrs.34let lock_handle = unsafe {35CreateMutexA(36/* lpMutexAttributes= */ null_mut(),37false as i32,38null_mut(),39)40};4142if lock_handle == INVALID_HANDLE_VALUE {43Err(Error::last())44} else {45Ok(Self {46// SAFETY:47// Safe because the handle is valid & we own it exclusively.48lock: unsafe { SafeDescriptor::from_raw_descriptor(lock_handle) },49})50}51}5253/// Locks the mutex, returning a RAII guard similar to std::sync::Mutex.54pub fn lock(&self) -> MultiProcessMutexGuard {55if let Some(guard) = self.try_lock(INFINITE) {56guard57} else {58// This should *never* happen.59panic!("Timed out locking mutex with an infinite timeout. This should never happen.");60}61}6263/// Tries to lock the mutex, returning a RAII guard similar to std::sync::Mutex if we obtained64/// the lock within the timeout.65pub fn try_lock(&self, timeout_ms: u32) -> Option<MultiProcessMutexGuard> {66// SAFETY:67// Safe because the mutex handle is guaranteed to exist.68match unsafe { WaitForSingleObject(self.lock.as_raw_descriptor(), timeout_ms) } {69WAIT_OBJECT_0 => Some(MultiProcessMutexGuard { lock: &self.lock }),70WAIT_TIMEOUT => None,71WAIT_ABANDONED => panic!(72"The thread holding the mutex exited without releasing the mutex.\73Protected data may be corrupt."74),75_ => {76// This should *never* happen.77panic!("Failed to lock mutex {:?}", Error::last())78}79}80}8182/// Creates a new reference to the mutex.83pub fn try_clone(&self) -> Result<Self> {84Ok(Self {85lock: self.lock.try_clone()?,86})87}88}8990/// RAII guard for MultiProcessMutex.91pub struct MultiProcessMutexGuard<'a> {92lock: &'a SafeDescriptor,93}9495impl Drop for MultiProcessMutexGuard<'_> {96fn drop(&mut self) {97// SAFETY: We own the descriptor and is expected to be valid.98if unsafe { ReleaseMutex(self.lock.as_raw_descriptor()) } == 0 {99panic!("Failed to unlock mutex: {:?}.", Error::last())100}101}102}103104105