]> git.proxmox.com Git - rustc.git/blame - vendor/rustc-ap-rustc_errors/src/lock.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / rustc-ap-rustc_errors / src / lock.rs
CommitLineData
f20569fa
XL
1//! Bindings to acquire a global named lock.
2//!
3//! This is intended to be used to synchronize multiple compiler processes to
4//! ensure that we can output complete errors without interleaving on Windows.
5//! Note that this is currently only needed for allowing only one 32-bit MSVC
6//! linker to execute at once on MSVC hosts, so this is only implemented for
7//! `cfg(windows)`. Also note that this may not always be used on Windows,
8//! only when targeting 32-bit MSVC.
9//!
10//! For more information about why this is necessary, see where this is called.
11
12use std::any::Any;
13
14#[cfg(windows)]
15pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
16 use std::ffi::CString;
17 use std::io;
18
19 use winapi::shared::ntdef::HANDLE;
20 use winapi::um::handleapi::CloseHandle;
21 use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
22 use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0};
23
24 struct Handle(HANDLE);
25
26 impl Drop for Handle {
27 fn drop(&mut self) {
28 unsafe {
29 CloseHandle(self.0);
30 }
31 }
32 }
33
34 struct Guard(Handle);
35
36 impl Drop for Guard {
37 fn drop(&mut self) {
38 unsafe {
39 ReleaseMutex((self.0).0);
40 }
41 }
42 }
43
44 let cname = CString::new(name).unwrap();
45 unsafe {
46 // Create a named mutex, with no security attributes and also not
47 // acquired when we create it.
48 //
49 // This will silently create one if it doesn't already exist, or it'll
50 // open up a handle to one if it already exists.
51 let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr());
52 if mutex.is_null() {
53 panic!(
54 "failed to create global mutex named `{}`: {}",
55 name,
56 io::Error::last_os_error()
57 );
58 }
59 let mutex = Handle(mutex);
60
61 // Acquire the lock through `WaitForSingleObject`.
62 //
63 // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
64 //
65 // A return value of `WAIT_ABANDONED` means that the previous holder of
66 // the thread exited without calling `ReleaseMutex`. This can happen,
67 // for example, when the compiler crashes or is interrupted via ctrl-c
68 // or the like. In this case, however, we are still transferred
69 // ownership of the lock so we continue.
70 //
71 // If an error happens.. well... that's surprising!
72 match WaitForSingleObject(mutex.0, INFINITE) {
73 WAIT_OBJECT_0 | WAIT_ABANDONED => {}
74 code => {
75 panic!(
76 "WaitForSingleObject failed on global mutex named \
77 `{}`: {} (ret={:x})",
78 name,
79 io::Error::last_os_error(),
80 code
81 );
82 }
83 }
84
85 // Return a guard which will call `ReleaseMutex` when dropped.
86 Box::new(Guard(mutex))
87 }
88}
89
90#[cfg(not(windows))]
91pub fn acquire_global_lock(_name: &str) -> Box<dyn Any> {
92 Box::new(())
93}