1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
8 | // option. This file may not be copied, modified, or distributed |
9 | // except according to those terms. |
10 | |
11 | //! Bindings to acquire a global named lock. |
12 | //! |
13 | //! This is intended to be used to synchronize multiple compiler processes to |
14 | //! ensure that we can output complete errors without interleaving on Windows. |
15 | //! Note that this is currently only needed for allowing only one 32-bit MSVC |
16 | //! linker to execute at once on MSVC hosts, so this is only implemented for |
17 | //! `cfg(windows)`. Also note that this may not always be used on Windows, |
18 | //! only when targeting 32-bit MSVC. |
19 | //! |
20 | //! For more information about why this is necessary, see where this is called. |
21 | |
22 | use std::any::Any; |
23 | |
24 | #[cfg (windows)] |
25 | #[allow (bad_style)] |
26 | pub fn acquire_global_lock(name: &str) -> Box<Any> { |
27 | use std::ffi::CString; |
28 | use std::io; |
29 | |
30 | type LPSECURITY_ATTRIBUTES = *mut u8; |
31 | type BOOL = i32; |
32 | type LPCSTR = *const u8; |
33 | type HANDLE = *mut u8; |
34 | type DWORD = u32; |
35 | |
36 | const INFINITE: DWORD = !0; |
37 | const WAIT_OBJECT_0: DWORD = 0; |
38 | const WAIT_ABANDONED: DWORD = 0x00000080; |
39 | |
40 | extern "system" { |
41 | fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES, |
42 | bInitialOwner: BOOL, |
43 | lpName: LPCSTR) |
44 | -> HANDLE; |
45 | fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; |
46 | fn ReleaseMutex(hMutex: HANDLE) -> BOOL; |
47 | fn CloseHandle(hObject: HANDLE) -> BOOL; |
48 | } |
49 | |
50 | struct Handle(HANDLE); |
51 | |
52 | impl Drop for Handle { |
53 | fn drop(&mut self) { |
54 | unsafe { |
55 | CloseHandle(self.0); |
56 | } |
57 | } |
58 | } |
59 | |
60 | struct Guard(Handle); |
61 | |
62 | impl Drop for Guard { |
63 | fn drop(&mut self) { |
64 | unsafe { |
65 | ReleaseMutex((self.0).0); |
66 | } |
67 | } |
68 | } |
69 | |
70 | let cname = CString::new(name).unwrap(); |
71 | unsafe { |
72 | // Create a named mutex, with no security attributes and also not |
73 | // acquired when we create it. |
74 | // |
75 | // This will silently create one if it doesn't already exist, or it'll |
76 | // open up a handle to one if it already exists. |
77 | let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8); |
78 | if mutex.is_null() { |
79 | panic!("failed to create global mutex named ` {}`: {}" , |
80 | name, |
81 | io::Error::last_os_error()); |
82 | } |
83 | let mutex = Handle(mutex); |
84 | |
85 | // Acquire the lock through `WaitForSingleObject`. |
86 | // |
87 | // A return value of `WAIT_OBJECT_0` means we successfully acquired it. |
88 | // |
89 | // A return value of `WAIT_ABANDONED` means that the previous holder of |
90 | // the thread exited without calling `ReleaseMutex`. This can happen, |
91 | // for example, when the compiler crashes or is interrupted via ctrl-c |
92 | // or the like. In this case, however, we are still transferred |
93 | // ownership of the lock so we continue. |
94 | // |
95 | // If an error happens.. well... that's surprising! |
96 | match WaitForSingleObject(mutex.0, INFINITE) { |
97 | WAIT_OBJECT_0 | WAIT_ABANDONED => {} |
98 | code => { |
99 | panic!("WaitForSingleObject failed on global mutex named \ |
100 | ` {}`: {} (ret= {:x})" , |
101 | name, |
102 | io::Error::last_os_error(), |
103 | code); |
104 | } |
105 | } |
106 | |
107 | // Return a guard which will call `ReleaseMutex` when dropped. |
108 | Box::new(Guard(mutex)) |
109 | } |
110 | } |
111 | |
112 | #[cfg (not(windows))] |
113 | pub fn acquire_global_lock(_name: &str) -> Box<Any> { |
114 | Box::new(()) |
115 | } |
116 | |