From 59855e0bbf0df22f39dbe39bc58ab5c978fb3765 Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Thu, 21 Jan 2021 12:13:35 -0800 Subject: [PATCH] Remove delay-binding for Win XP and Vista 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" https://github.com/rust-lang/compiler-team/issues/378 * "Firefox has ended support for Windows XP and Vista" https://support.mozilla.org/en-US/kb/end-support-windows-xp-and-vista --- library/std/src/sys/windows/c.rs | 116 +++++++++++++++------------ library/std/src/sys/windows/mutex.rs | 110 +++++-------------------- 2 files changed, 81 insertions(+), 145 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 2b1bc92dc84ae..f43a19d91b657 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1020,6 +1020,60 @@ 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, @@ -1027,70 +1081,26 @@ extern "system" { 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, diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index d4cc56d4cb3ef..72a0993d94ddf 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -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 otherwise. - lock: AtomicUsize, + srwlock: UnsafeCell, } // Windows SRW Locks are movable (while not borrowed). @@ -37,106 +30,39 @@ pub type MovableMutex = Mutex; unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} -struct Inner { - remutex: ReentrantMutex, - held: Cell, -} - -#[derive(Clone, Copy)] -enum Kind { - SRWLock, - CriticalSection, -} - #[inline] pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { - debug_assert!(mem::size_of::() <= 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>, }