-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
prevent error message interleaving on win/unix
- Loading branch information
Jonathan Turner
committed
Aug 25, 2016
1 parent
17a2be8
commit a65b201
Showing
3 changed files
with
198 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! Bindings to acquire a global named lock. | ||
//! | ||
//! This is intended to be used to synchronize multiple compiler processes to | ||
//! ensure that we can output complete errors without interleaving on Windows. | ||
//! Note that this is currently only needed for allowing only one 32-bit MSVC | ||
//! linker to execute at once on MSVC hosts, so this is only implemented for | ||
//! `cfg(windows)`. Also note that this may not always be used on Windows, | ||
//! only when targeting 32-bit MSVC. | ||
//! | ||
//! For more information about why this is necessary, see where this is called. | ||
use std::any::Any; | ||
|
||
#[cfg(windows)] | ||
#[allow(bad_style)] | ||
pub fn acquire_global_lock(name: &str) -> Box<Any> { | ||
use std::ffi::CString; | ||
use std::io; | ||
|
||
type LPSECURITY_ATTRIBUTES = *mut u8; | ||
type BOOL = i32; | ||
type LPCSTR = *const u8; | ||
type HANDLE = *mut u8; | ||
type DWORD = u32; | ||
|
||
const INFINITE: DWORD = !0; | ||
const WAIT_OBJECT_0: DWORD = 0; | ||
const WAIT_ABANDONED: DWORD = 0x00000080; | ||
|
||
extern "system" { | ||
fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES, | ||
bInitialOwner: BOOL, | ||
lpName: LPCSTR) -> HANDLE; | ||
fn WaitForSingleObject(hHandle: HANDLE, | ||
dwMilliseconds: DWORD) -> DWORD; | ||
fn ReleaseMutex(hMutex: HANDLE) -> BOOL; | ||
fn CloseHandle(hObject: HANDLE) -> BOOL; | ||
} | ||
|
||
struct Handle(HANDLE); | ||
|
||
impl Drop for Handle { | ||
fn drop(&mut self) { | ||
unsafe { | ||
CloseHandle(self.0); | ||
} | ||
} | ||
} | ||
|
||
struct Guard(Handle); | ||
|
||
impl Drop for Guard { | ||
fn drop(&mut self) { | ||
unsafe { | ||
ReleaseMutex((self.0).0); | ||
} | ||
} | ||
} | ||
|
||
let cname = CString::new(name).unwrap(); | ||
unsafe { | ||
// Create a named mutex, with no security attributes and also not | ||
// acquired when we create it. | ||
// | ||
// This will silently create one if it doesn't already exist, or it'll | ||
// open up a handle to one if it already exists. | ||
let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8); | ||
if mutex.is_null() { | ||
panic!("failed to create global mutex named `{}`: {}", name, | ||
io::Error::last_os_error()); | ||
} | ||
let mutex = Handle(mutex); | ||
|
||
// Acquire the lock through `WaitForSingleObject`. | ||
// | ||
// A return value of `WAIT_OBJECT_0` means we successfully acquired it. | ||
// | ||
// A return value of `WAIT_ABANDONED` means that the previous holder of | ||
// the thread exited without calling `ReleaseMutex`. This can happen, | ||
// for example, when the compiler crashes or is interrupted via ctrl-c | ||
// or the like. In this case, however, we are still transferred | ||
// ownership of the lock so we continue. | ||
// | ||
// If an error happens.. well... that's surprising! | ||
match WaitForSingleObject(mutex.0, INFINITE) { | ||
WAIT_OBJECT_0 | WAIT_ABANDONED => {} | ||
code => { | ||
panic!("WaitForSingleObject failed on global mutex named \ | ||
`{}`: {} (ret={:x})", name, | ||
io::Error::last_os_error(), code); | ||
} | ||
} | ||
|
||
// Return a guard which will call `ReleaseMutex` when dropped. | ||
Box::new(Guard(mutex)) | ||
} | ||
} | ||
|
||
#[cfg(unix)] | ||
pub fn acquire_global_lock(_name: &str) -> Box<Any> { | ||
Box::new(()) | ||
} |