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