Skip to content

Commit

Permalink
Remove delay-binding for Win XP and Vista
Browse files Browse the repository at this point in the history
The minimum supported Windows version is now Windows 7. Windows XP
and Windows Vista are no longer supported; both are already broken, and
require extra steps to use.

This commit removes the delayed-binding support for Windows API
functions that are present on all supported Windows targets. This has
several benefits: Removes needless complexity. Removes a load and
dynamic call on hot paths in mutex acquire / release. This may have
performance benefits.

* "Drop official support for Windows XP"
  rust-lang/compiler-team#378

* "Firefox has ended support for Windows XP and Vista"
  https://support.mozilla.org/en-US/kb/end-support-windows-xp-and-vista
  • Loading branch information
Arlie Davis committed Jan 22, 2021
1 parent 25f39fe commit 59855e0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 145 deletions.
116 changes: 63 additions & 53 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,77 +1020,87 @@ extern "system" {
pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;

// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinka
pub fn CreateSymbolicLinkW(
lpSymlinkFileName: LPCWSTR,
lpTargetFileName: LPCWSTR,
dwFlags: DWORD,
) -> BOOLEAN;

// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
pub fn GetFinalPathNameByHandleW(
hFile: HANDLE,
lpszFilePath: LPCWSTR,
cchFilePath: DWORD,
dwFlags: DWORD,
) -> DWORD;

// >= Vista / Server 2003
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee
#[cfg(not(target_vendor = "uwp"))]
pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;

// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
pub fn SetFileInformationByHandle(
hFile: HANDLE,
FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
lpFileInformation: LPVOID,
dwBufferSize: DWORD,
) -> BOOL;

// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw
pub fn SleepConditionVariableSRW(
ConditionVariable: PCONDITION_VARIABLE,
SRWLock: PSRWLOCK,
dwMilliseconds: DWORD,
Flags: ULONG,
) -> BOOL;

// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable
pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE);

// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive
pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK);
pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK);
pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK);
pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK);
pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN;
pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN;
}

// Functions that aren't available on every version of Windows that we support,
// but we still use them and just provide some form of a fallback implementation.
compat_fn! {
"kernel32":

pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
_lpTargetFileName: LPCWSTR,
_dwFlags: DWORD) -> BOOLEAN {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
}
pub fn GetFinalPathNameByHandleW(_hFile: HANDLE,
_lpszFilePath: LPCWSTR,
_cchFilePath: DWORD,
_dwFlags: DWORD) -> DWORD {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
}
#[cfg(not(target_vendor = "uwp"))]
pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
}
// >= Win10 1607
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
pub fn SetThreadDescription(hThread: HANDLE,
lpThreadDescription: LPCWSTR) -> HRESULT {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
}
pub fn SetFileInformationByHandle(_hFile: HANDLE,
_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
_lpFileInformation: LPVOID,
_dwBufferSize: DWORD) -> BOOL {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
}

// >= Win8 / Server 2012
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME)
-> () {
GetSystemTimeAsFileTime(lpSystemTimeAsFileTime)
}
pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE,
SRWLock: PSRWLOCK,
dwMilliseconds: DWORD,
Flags: ULONG) -> BOOL {
panic!("condition variables not available")
}
pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE)
-> () {
panic!("condition variables not available")
}
pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE)
-> () {
panic!("condition variables not available")
}
pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () {
panic!("rwlocks not available")
}
pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () {
panic!("rwlocks not available")
}
pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () {
panic!("rwlocks not available")
}
pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () {
panic!("rwlocks not available")
}
pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN {
panic!("rwlocks not available")
}
pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN {
panic!("rwlocks not available")
}
}

compat_fn! {
"api-ms-win-core-synch-l1-2-0":

// >= Windows 8 / Server 2012
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress
pub fn WaitOnAddress(
Address: LPVOID,
CompareAddress: LPVOID,
Expand Down
110 changes: 18 additions & 92 deletions library/std/src/sys/windows/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,13 @@
//!
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
//! is that there are no guarantees of fairness.
//!
//! The downside of this approach, however, is that SRWLock is not available on
//! Windows XP, so we continue to have a fallback implementation where
//! CriticalSection is used and we keep track of who's holding the mutex to
//! detect recursive locks.

use crate::cell::{Cell, UnsafeCell};
use crate::mem::{self, MaybeUninit};
use crate::sync::atomic::{AtomicUsize, Ordering};

use crate::cell::UnsafeCell;
use crate::mem::MaybeUninit;
use crate::sys::c;

pub struct Mutex {
// This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise.
lock: AtomicUsize,
srwlock: UnsafeCell<c::SRWLOCK>,
}

// Windows SRW Locks are movable (while not borrowed).
Expand All @@ -37,106 +30,39 @@ pub type MovableMutex = Mutex;
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

struct Inner {
remutex: ReentrantMutex,
held: Cell<bool>,
}

#[derive(Clone, Copy)]
enum Kind {
SRWLock,
CriticalSection,
}

#[inline]
pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock));
&m.lock as *const _ as *mut _
m.srwlock.get()
}

impl Mutex {
pub const fn new() -> Mutex {
Mutex {
// This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly
// initializing an SRWLOCK here.
lock: AtomicUsize::new(0),
}
Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) }
}
#[inline]
pub unsafe fn init(&mut self) {}

#[inline]
pub unsafe fn lock(&self) {
match kind() {
Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
Kind::CriticalSection => {
let inner = &*self.inner();
inner.remutex.lock();
if inner.held.replace(true) {
// It was already locked, so we got a recursive lock which we do not want.
inner.remutex.unlock();
panic!("cannot recursively lock a mutex");
}
}
}
c::AcquireSRWLockExclusive(raw(self));
}

#[inline]
pub unsafe fn try_lock(&self) -> bool {
match kind() {
Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0,
Kind::CriticalSection => {
let inner = &*self.inner();
if !inner.remutex.try_lock() {
false
} else if inner.held.replace(true) {
// It was already locked, so we got a recursive lock which we do not want.
inner.remutex.unlock();
false
} else {
true
}
}
}
c::TryAcquireSRWLockExclusive(raw(self)) != 0
}

#[inline]
pub unsafe fn unlock(&self) {
match kind() {
Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)),
Kind::CriticalSection => {
let inner = &*(self.lock.load(Ordering::SeqCst) as *const Inner);
inner.held.set(false);
inner.remutex.unlock();
}
}
}
pub unsafe fn destroy(&self) {
match kind() {
Kind::SRWLock => {}
Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) {
0 => {}
n => Box::from_raw(n as *mut Inner).remutex.destroy(),
},
}
c::ReleaseSRWLockExclusive(raw(self));
}

unsafe fn inner(&self) -> *const Inner {
match self.lock.load(Ordering::SeqCst) {
0 => {}
n => return n as *const _,
}
let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) };
inner.remutex.init();
let inner = Box::into_raw(inner);
match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) {
Ok(_) => inner,
Err(n) => {
Box::from_raw(inner).remutex.destroy();
n as *const _
}
}
#[inline]
pub unsafe fn destroy(&self) {
// SRWLock does not need to be destroyed.
}
}

fn kind() -> Kind {
if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection }
}

pub struct ReentrantMutex {
inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>>,
}
Expand Down

0 comments on commit 59855e0

Please sign in to comment.