Skip to content

Commit 08798a9

Browse files
committed
Add downlevel implementations for Mutex, CondVar and RwLock
Because of the movability and const-initialization requirements, the implementation uses LazyBox. OnceLock cannot be used here as it needs a thread parker. The windows-specific thread parker is XP+ only, and the generic thread parker is implemented in tems of a condvar, which would make this a circular dependency. - Fall back to critical sections on NT4+, and `CreateMutex` objects for everything else. OnceLock is used to do the necessary initialization for these fallback implementations. - Implement `RwLock` fallback by dropping down to a `Mutex`. - Implement `CondVar` fallback based on `CreateEventA`/`PulseEvent`. This should be used with extreme caution as it may cause deadlocks. See which may cause deadlocks. See [Old New Thing](https://devblogs.microsoft.com/oldnewthing/20050105-00/?p=36803) and the [MSDN docs](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-pulseevent) for more information.
1 parent 643bd55 commit 08798a9

File tree

12 files changed

+660
-45
lines changed

12 files changed

+660
-45
lines changed

library/std/src/sys/windows/c.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ pub type LPWCH = *mut WCHAR;
3838
pub type LPWSTR = *mut WCHAR;
3939

4040
pub type PLARGE_INTEGER = *mut c_longlong;
41-
pub type PSRWLOCK = *mut SRWLOCK;
4241

4342
pub type socklen_t = c_int;
4443
pub type ADDRESS_FAMILY = USHORT;
@@ -355,6 +354,35 @@ compat_fn_optional! {
355354
pub fn WakeByAddressSingle(address: *const ::core::ffi::c_void);
356355
}
357356

357+
compat_fn_optional! {
358+
crate::sys::compat::load_try_enter_critical_section_function();
359+
// >= NT 4
360+
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-tryentercriticalsection
361+
pub fn TryEnterCriticalSection(lpcriticalsection: *mut CRITICAL_SECTION) -> BOOL;
362+
}
363+
364+
compat_fn_optional! {
365+
crate::sys::compat::load_srw_functions();
366+
// >= Win7 / Server 2008 R2
367+
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-tryacquiresrwlockexclusive
368+
pub fn TryAcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> BOOLEAN;
369+
pub fn TryAcquireSRWLockShared(srwlock: *mut SRWLOCK) -> BOOLEAN;
370+
// >= Vista / Server 2008
371+
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive
372+
pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
373+
pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK) -> ();
374+
pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
375+
pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK) -> ();
376+
pub fn SleepConditionVariableSRW(
377+
conditionvariable: *mut CONDITION_VARIABLE,
378+
srwlock: *mut SRWLOCK,
379+
dwmilliseconds: u32,
380+
flags: u32,
381+
) -> BOOL;
382+
pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> ();
383+
pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> ();
384+
}
385+
358386
compat_fn_with_fallback! {
359387
pub static NTDLL: &CStr = c"ntdll" => { load: true, unicows: false };
360388

library/std/src/sys/windows/c/windows_sys.lst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,3 +2595,16 @@ Windows.Win32.UI.Shell.GetUserProfileDirectoryW
25952595
// tidy-alphabetical-end
25962596

25972597
Windows.Win32.System.LibraryLoader.LoadLibraryA
2598+
2599+
// sync primitives
2600+
Windows.Win32.System.Threading.CreateMutexA
2601+
Windows.Win32.System.Threading.ReleaseMutex
2602+
Windows.Win32.System.Threading.CreateEventA
2603+
Windows.Win32.System.Threading.PulseEvent
2604+
Windows.Win32.System.Threading.CRITICAL_SECTION
2605+
Windows.Win32.System.Threading.InitializeCriticalSection
2606+
Windows.Win32.System.Threading.EnterCriticalSection
2607+
Windows.Win32.System.Threading.LeaveCriticalSection
2608+
Windows.Win32.System.Threading.DeleteCriticalSection
2609+
Windows.Win32.System.Threading.SRWLOCK
2610+
Windows.Win32.System.Threading.CONDITION_VARIABLE

library/std/src/sys/windows/c/windows_sys.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ extern "system" {
7575
) -> BOOL;
7676
}
7777
#[link(name = "kernel32")]
78+
extern "system" {
79+
pub fn CreateEventA(
80+
lpeventattributes: *const SECURITY_ATTRIBUTES,
81+
bmanualreset: BOOL,
82+
binitialstate: BOOL,
83+
lpname: PCSTR,
84+
) -> HANDLE;
85+
}
86+
#[link(name = "kernel32")]
7887
extern "system" {
7988
pub fn CreateEventW(
8089
lpeventattributes: *const SECURITY_ATTRIBUTES,
@@ -104,6 +113,14 @@ extern "system" {
104113
) -> BOOL;
105114
}
106115
#[link(name = "kernel32")]
116+
extern "system" {
117+
pub fn CreateMutexA(
118+
lpmutexattributes: *const SECURITY_ATTRIBUTES,
119+
binitialowner: BOOL,
120+
lpname: PCSTR,
121+
) -> HANDLE;
122+
}
123+
#[link(name = "kernel32")]
107124
extern "system" {
108125
pub fn CreateNamedPipeW(
109126
lpname: PCWSTR,
@@ -160,6 +177,10 @@ extern "system" {
160177
) -> HANDLE;
161178
}
162179
#[link(name = "kernel32")]
180+
extern "system" {
181+
pub fn DeleteCriticalSection(lpcriticalsection: *mut CRITICAL_SECTION) -> ();
182+
}
183+
#[link(name = "kernel32")]
163184
extern "system" {
164185
pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
165186
}
@@ -193,6 +214,10 @@ extern "system" {
193214
) -> BOOL;
194215
}
195216
#[link(name = "kernel32")]
217+
extern "system" {
218+
pub fn EnterCriticalSection(lpcriticalsection: *mut CRITICAL_SECTION) -> ();
219+
}
220+
#[link(name = "kernel32")]
196221
extern "system" {
197222
pub fn ExitProcess(uexitcode: u32) -> !;
198223
}
@@ -385,6 +410,10 @@ extern "system" {
385410
) -> BOOL;
386411
}
387412
#[link(name = "kernel32")]
413+
extern "system" {
414+
pub fn InitializeCriticalSection(lpcriticalsection: *mut CRITICAL_SECTION) -> ();
415+
}
416+
#[link(name = "kernel32")]
388417
extern "system" {
389418
pub fn InitializeProcThreadAttributeList(
390419
lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
@@ -394,6 +423,10 @@ extern "system" {
394423
) -> BOOL;
395424
}
396425
#[link(name = "kernel32")]
426+
extern "system" {
427+
pub fn LeaveCriticalSection(lpcriticalsection: *mut CRITICAL_SECTION) -> ();
428+
}
429+
#[link(name = "kernel32")]
397430
extern "system" {
398431
pub fn LoadLibraryA(lplibfilename: PCSTR) -> HMODULE;
399432
}
@@ -417,6 +450,10 @@ extern "system" {
417450
) -> i32;
418451
}
419452
#[link(name = "kernel32")]
453+
extern "system" {
454+
pub fn PulseEvent(hevent: HANDLE) -> BOOL;
455+
}
456+
#[link(name = "kernel32")]
420457
extern "system" {
421458
pub fn QueryPerformanceCounter(lpperformancecount: *mut i64) -> BOOL;
422459
}
@@ -455,6 +492,10 @@ extern "system" {
455492
) -> BOOL;
456493
}
457494
#[link(name = "kernel32")]
495+
extern "system" {
496+
pub fn ReleaseMutex(hmutex: HANDLE) -> BOOL;
497+
}
498+
#[link(name = "kernel32")]
458499
extern "system" {
459500
pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
460501
}
@@ -1191,6 +1232,39 @@ pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32;
11911232
pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32;
11921233
pub const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: u32 = 2u32;
11931234
pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: u32 = 1u32;
1235+
#[repr(C)]
1236+
pub struct CRITICAL_SECTION {
1237+
pub DebugInfo: *mut CRITICAL_SECTION_DEBUG,
1238+
pub LockCount: i32,
1239+
pub RecursionCount: i32,
1240+
pub OwningThread: HANDLE,
1241+
pub LockSemaphore: HANDLE,
1242+
pub SpinCount: usize,
1243+
}
1244+
impl ::core::marker::Copy for CRITICAL_SECTION {}
1245+
impl ::core::clone::Clone for CRITICAL_SECTION {
1246+
fn clone(&self) -> Self {
1247+
*self
1248+
}
1249+
}
1250+
#[repr(C)]
1251+
pub struct CRITICAL_SECTION_DEBUG {
1252+
pub Type: u16,
1253+
pub CreatorBackTraceIndex: u16,
1254+
pub CriticalSection: *mut CRITICAL_SECTION,
1255+
pub ProcessLocksList: LIST_ENTRY,
1256+
pub EntryCount: u32,
1257+
pub ContentionCount: u32,
1258+
pub Flags: u32,
1259+
pub CreatorBackTraceIndexHigh: u16,
1260+
pub Identifier: u16,
1261+
}
1262+
impl ::core::marker::Copy for CRITICAL_SECTION_DEBUG {}
1263+
impl ::core::clone::Clone for CRITICAL_SECTION_DEBUG {
1264+
fn clone(&self) -> Self {
1265+
*self
1266+
}
1267+
}
11941268
pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32;
11951269
pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32;
11961270
pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32;
@@ -3653,6 +3727,17 @@ impl ::core::clone::Clone for LINGER {
36533727
*self
36543728
}
36553729
}
3730+
#[repr(C)]
3731+
pub struct LIST_ENTRY {
3732+
pub Flink: *mut LIST_ENTRY,
3733+
pub Blink: *mut LIST_ENTRY,
3734+
}
3735+
impl ::core::marker::Copy for LIST_ENTRY {}
3736+
impl ::core::clone::Clone for LIST_ENTRY {
3737+
fn clone(&self) -> Self {
3738+
*self
3739+
}
3740+
}
36563741
pub type LPOVERLAPPED_COMPLETION_ROUTINE = ::core::option::Option<
36573742
unsafe extern "system" fn(
36583743
dwerrorcode: u32,

library/std/src/sys/windows/compat.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ unsafe extern "C" fn init() {
6363
// because this function runs during global initialization. For example, DO NOT
6464
// do any dynamic allocation, don't call LoadLibrary, etc.
6565

66+
// check all the different synchronization primitives ...
67+
load_try_enter_critical_section_function();
68+
load_srw_functions();
69+
// ... and init mutex downlevel compat based on it
70+
super::locks::compat::init();
71+
6672
// Attempt to preload the synch functions.
6773
load_synch_functions();
6874
#[cfg(not(target_vendor = "uwp"))]
@@ -405,3 +411,45 @@ pub(super) fn load_stack_overflow_functions() {
405411

406412
try_load();
407413
}
414+
415+
pub(super) fn load_try_enter_critical_section_function() {
416+
fn try_load() -> Option<()> {
417+
const MODULE_NAME: &CStr = c"kernel32";
418+
419+
let library = unsafe { Module::new(MODULE_NAME) }?;
420+
static_load!(library, [TryEnterCriticalSection]);
421+
Some(())
422+
}
423+
424+
try_load();
425+
}
426+
427+
pub(super) fn load_srw_functions() {
428+
fn try_load() -> Option<()> {
429+
const MODULE_NAME: &CStr = c"kernel32";
430+
431+
// Try loading the library and all the required functions.
432+
// If any step fails, then they all fail.
433+
let library = unsafe { Module::new(MODULE_NAME) }?;
434+
435+
static_load!(
436+
library,
437+
[
438+
// check the try_ functions first, as they have higher system requirements
439+
TryAcquireSRWLockExclusive,
440+
TryAcquireSRWLockShared,
441+
AcquireSRWLockExclusive,
442+
AcquireSRWLockShared,
443+
ReleaseSRWLockExclusive,
444+
ReleaseSRWLockShared,
445+
SleepConditionVariableSRW,
446+
WakeAllConditionVariable,
447+
WakeConditionVariable
448+
]
449+
);
450+
451+
Some(())
452+
}
453+
454+
try_load();
455+
}

0 commit comments

Comments
 (0)