| 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<dynAny> { |
| 114 | Box::new(()) |
| 115 | } |
| 116 | |