]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/lock.rs
Rollup merge of #67313 - oli-obk:document_all_the_t̶h̶i̶n̶g̶s̶dataflow, r=ecstatic...
[rust.git] / src / librustc_errors / lock.rs
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
12 use std::any::Any;
13
14 #[cfg(windows)]
15 #[allow(nonstandard_style)]
16 pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
17     use std::ffi::CString;
18     use std::io;
19
20     type LPSECURITY_ATTRIBUTES = *mut u8;
21     type BOOL = i32;
22     type LPCSTR = *const u8;
23     type HANDLE = *mut u8;
24     type DWORD = u32;
25
26     const INFINITE: DWORD = !0;
27     const WAIT_OBJECT_0: DWORD = 0;
28     const WAIT_ABANDONED: DWORD = 0x00000080;
29
30     extern "system" {
31         fn CreateMutexA(
32             lpMutexAttributes: LPSECURITY_ATTRIBUTES,
33             bInitialOwner: BOOL,
34             lpName: LPCSTR,
35         ) -> HANDLE;
36         fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
37         fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
38         fn CloseHandle(hObject: HANDLE) -> BOOL;
39     }
40
41     struct Handle(HANDLE);
42
43     impl Drop for Handle {
44         fn drop(&mut self) {
45             unsafe {
46                 CloseHandle(self.0);
47             }
48         }
49     }
50
51     struct Guard(Handle);
52
53     impl Drop for Guard {
54         fn drop(&mut self) {
55             unsafe {
56                 ReleaseMutex((self.0).0);
57             }
58         }
59     }
60
61     let cname = CString::new(name).unwrap();
62     unsafe {
63         // Create a named mutex, with no security attributes and also not
64         // acquired when we create it.
65         //
66         // This will silently create one if it doesn't already exist, or it'll
67         // open up a handle to one if it already exists.
68         let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr() as *const u8);
69         if mutex.is_null() {
70             panic!(
71                 "failed to create global mutex named `{}`: {}",
72                 name,
73                 io::Error::last_os_error()
74             );
75         }
76         let mutex = Handle(mutex);
77
78         // Acquire the lock through `WaitForSingleObject`.
79         //
80         // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
81         //
82         // A return value of `WAIT_ABANDONED` means that the previous holder of
83         // the thread exited without calling `ReleaseMutex`. This can happen,
84         // for example, when the compiler crashes or is interrupted via ctrl-c
85         // or the like. In this case, however, we are still transferred
86         // ownership of the lock so we continue.
87         //
88         // If an error happens.. well... that's surprising!
89         match WaitForSingleObject(mutex.0, INFINITE) {
90             WAIT_OBJECT_0 | WAIT_ABANDONED => {}
91             code => {
92                 panic!(
93                     "WaitForSingleObject failed on global mutex named \
94                         `{}`: {} (ret={:x})",
95                     name,
96                     io::Error::last_os_error(),
97                     code
98                 );
99             }
100         }
101
102         // Return a guard which will call `ReleaseMutex` when dropped.
103         Box::new(Guard(mutex))
104     }
105 }
106
107 #[cfg(not(windows))]
108 pub fn acquire_global_lock(_name: &str) -> Box<dyn Any> {
109     Box::new(())
110 }