-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit enables executables linked against the standard library to run on Windows XP. There are two main components of this commit: * APIs not available on XP are shimmed to have a fallback implementation and use runtime detection to determine if they are available. * Mutexes on Windows were reimplemented to use critical sections on XP where rwlocks are not available. The APIs which are not available on XP are: * SetFileInformationByHandle - this is just used by `File::truncate` and that function just returns an error now. * SetThreadStackGuarantee - this is used by the stack overflow support on windows, but if this isn't available then it's just ignored (it seems non-critical). * All condition variable APIs are missing - the shims added for these apis simply always panic for now. We may eventually provide a fallback implementation, but for now the standard library does not rely on condition variables for normal use. * RWLocks, like condition variables, are missing entirely. The same story for condition variables is taken here. These APIs are all now panicking stubs as the standard library doesn't rely on RWLocks for normal use. Currently, as an optimization, we use SRWLOCKs for the standard `sync::Mutex` implementation on Windows, which is indeed required for normal operation of the standard library. To allow the standard library to run on XP, this commit reimplements mutexes on Windows to use SRWLOCK instances *if available* and otherwise a CriticalSection is used (with some checking for recursive locking). With all these changes put together, a 32-bit MSVC-built executable can run on Windows XP and print "hello world" Closes #12842 Closes #19992 Closes #24776
- Loading branch information
1 parent
8790958
commit 10b103a
Showing
10 changed files
with
353 additions
and
243 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,88 @@ | ||
// Copyright 2014 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. | ||
|
||
//! A "compatibility layer" for spanning XP and Windows 7 | ||
//! | ||
//! The standard library currently binds many functions that are not available | ||
//! on Windows XP, but we would also like to support building executables that | ||
//! run on XP. To do this we specify all non-XP APIs as having a fallback | ||
//! implementation to do something reasonable. | ||
//! | ||
//! This dynamic runtime detection of whether a function is available is | ||
//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a | ||
//! static-per-function which caches the result of the first check. In this | ||
//! manner we pay a semi-large one-time cost up front for detecting whether a | ||
//! function is available but afterwards it's just a load and a jump. | ||
use prelude::v1::*; | ||
|
||
use ffi::CString; | ||
use libc::{LPVOID, LPCWSTR, HMODULE, LPCSTR}; | ||
use sync::atomic::{AtomicUsize, Ordering}; | ||
|
||
extern "system" { | ||
fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; | ||
fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; | ||
} | ||
|
||
pub fn lookup(module: &str, symbol: &str) -> Option<usize> { | ||
let mut module: Vec<u16> = module.utf16_units().collect(); | ||
module.push(0); | ||
let symbol = CString::new(symbol).unwrap(); | ||
unsafe { | ||
let handle = GetModuleHandleW(module.as_ptr()); | ||
match GetProcAddress(handle, symbol.as_ptr()) as usize { | ||
0 => None, | ||
n => Some(n), | ||
} | ||
} | ||
} | ||
|
||
pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, | ||
fallback: usize) -> usize { | ||
let value = lookup(module, symbol).unwrap_or(fallback); | ||
ptr.store(value, Ordering::SeqCst); | ||
value | ||
} | ||
|
||
macro_rules! compat_fn { | ||
($module:ident: $( | ||
pub fn $symbol:ident($($argname:ident: $argtype:ty),*) | ||
-> $rettype:ty { | ||
$($body:expr);* | ||
} | ||
)*) => ($( | ||
#[allow(unused_variables)] | ||
pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { | ||
use sync::atomic::{AtomicUsize, Ordering}; | ||
use mem; | ||
type F = unsafe extern "system" fn($($argtype),*) -> $rettype; | ||
|
||
static PTR: AtomicUsize = AtomicUsize::new(0); | ||
|
||
fn load() -> usize { | ||
::sys::compat::store_func(&PTR, | ||
stringify!($module), | ||
stringify!($symbol), | ||
fallback as usize) | ||
} | ||
unsafe extern "system" fn fallback($($argname: $argtype),*) | ||
-> $rettype { | ||
$($body);* | ||
} | ||
|
||
let addr = match PTR.load(Ordering::SeqCst) { | ||
0 => load(), | ||
n => n, | ||
}; | ||
mem::transmute::<usize, F>(addr)($($argname),*) | ||
} | ||
)*) | ||
} |
Oops, something went wrong.