Skip to content

Commit 16aaea2

Browse files
committed
Add more compat_fn machinery
1 parent 2e73e10 commit 16aaea2

File tree

4 files changed

+107
-24
lines changed

4 files changed

+107
-24
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#![unstable(issue = "none", feature = "windows_c")]
66
#![allow(clippy::style)]
77

8-
use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void};
8+
use core::ffi::{c_uint, c_ulong, c_ushort, c_void};
99
use core::{mem, ptr};
1010

1111
mod windows_sys;
@@ -122,7 +122,7 @@ extern "system" {
122122
// Functions that aren't available on every version of Windows that we support,
123123
// but we still use them and just provide some form of a fallback implementation.
124124
compat_fn_with_fallback! {
125-
pub static KERNEL32: &CStr = c"kernel32";
125+
pub static KERNEL32: &CStr = c"kernel32" => { load: false, unicows: false };
126126

127127
// >= Win10 1607
128128
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
@@ -189,7 +189,7 @@ compat_fn_optional! {
189189

190190
#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))]
191191
compat_fn_with_fallback! {
192-
pub static NTDLL: &CStr = c"ntdll";
192+
pub static NTDLL: &CStr = c"ntdll" => { load: true, unicows: false };
193193

194194
#[cfg(target_vendor = "win7")]
195195
pub fn NtCreateKeyedEvent(

library/std/src/sys/pal/windows/c/bindings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2475,6 +2475,7 @@ Windows.Win32.System.LibraryLoader.GetModuleFileNameW
24752475
Windows.Win32.System.LibraryLoader.GetModuleHandleA
24762476
Windows.Win32.System.LibraryLoader.GetModuleHandleW
24772477
Windows.Win32.System.LibraryLoader.GetProcAddress
2478+
Windows.Win32.System.LibraryLoader.LoadLibraryA
24782479
Windows.Win32.System.Performance.QueryPerformanceCounter
24792480
Windows.Win32.System.Performance.QueryPerformanceFrequency
24802481
Windows.Win32.System.Pipes.CreateNamedPipeW

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer
6565
windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
6666
windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
6767
windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
68+
windows_targets::link!("kernel32.dll" "system" fn LoadLibraryA(lplibfilename : PCSTR) -> HMODULE);
6869
windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
6970
windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
7071
windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);

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

Lines changed: 102 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::sys::c;
3737
// file an issue for discussion; currently we don't guarantee any functionality
3838
// before main.
3939
// See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170
40-
#[cfg(target_vendor = "win7")]
40+
#[cfg(any(target_vendor = "win7", target_vendor = "rust9x"))]
4141
#[used]
4242
#[link_section = ".CRT$XCT"]
4343
static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
@@ -68,6 +68,21 @@ unsafe extern "C" fn init() {
6868
load_synch_functions();
6969
}
7070

71+
#[cfg(target_vendor = "rust9x")]
72+
unsafe extern "C" fn init() {
73+
// In an exe this code is executed before main() so is single threaded.
74+
// In a DLL the system's loader lock will be held thereby synchronizing
75+
// access. So the same best practices apply here as they do to running in DllMain:
76+
// https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
77+
//
78+
// DO NOT do anything interesting or complicated in this function! DO NOT call
79+
// any Rust functions or CRT functions if those functions touch any global state,
80+
// because this function runs during global initialization. For example, DO NOT
81+
// do any dynamic allocation, don't call LoadLibrary, etc.
82+
83+
checks::init_rust9x_checks();
84+
}
85+
7186
/// Helper macro for creating CStrs from literals and symbol names.
7287
macro_rules! ansi_str {
7388
(sym $ident:ident) => {{ crate::sys::compat::const_cstr_from_bytes(concat!(stringify!($ident), "\0").as_bytes()) }};
@@ -118,6 +133,15 @@ impl Module {
118133
}
119134
}
120135

136+
#[allow(dead_code)]
137+
pub unsafe fn load(name: &CStr) -> Option<Self> {
138+
// SAFETY: A CStr is always null terminated.
139+
unsafe {
140+
let module = c::LoadLibraryA(name.as_ptr().cast::<u8>());
141+
NonNull::new(module).map(Self)
142+
}
143+
}
144+
121145
// Try to get the address of a function.
122146
pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> {
123147
unsafe {
@@ -131,43 +155,54 @@ impl Module {
131155
}
132156
}
133157

158+
pub static UNICOWS: &CStr = c"unicows";
159+
134160
/// Load a function or use a fallback implementation if that fails.
135161
macro_rules! compat_fn_with_fallback {
136-
(pub static $module:ident: &CStr = $name:expr; $(
137-
$(#[$meta:meta])*
138-
$vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
139-
)*) => (
140-
pub static $module: &CStr = $name;
162+
{
163+
pub static $module:ident: &CStr = $name:expr => { load: $load:expr, unicows: $unicows:expr };
164+
$(
165+
$(#[$meta:meta])*
166+
$vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),* $(,)?) $(-> $rettype:ty)? $fallback_body:block
167+
)*
168+
} => {
141169
$(
142170
$(#[$meta])*
143171
pub mod $symbol {
144172
#[allow(unused_imports)]
145173
use super::*;
146174
use crate::mem;
147-
use crate::ffi::CStr;
175+
use crate::ffi::{CStr, c_void};
148176
use crate::sync::atomic::{AtomicPtr, Ordering};
149-
use crate::sys::compat::Module;
150177

151-
type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
178+
type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?;
152179

153180
/// `PTR` contains a function pointer to one of three functions.
154181
/// It starts with the `load` function.
155182
/// When that is called it attempts to load the requested symbol.
156183
/// If it succeeds, `PTR` is set to the address of that symbol.
157184
/// If it fails, then `PTR` is set to `fallback`.
158-
static PTR: AtomicPtr<c_void> = AtomicPtr::new(load as *mut _);
185+
pub(in crate::sys) static PTR: AtomicPtr<c_void> = AtomicPtr::new(load as *mut _);
159186

160-
unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype {
187+
unsafe extern "system" fn load($($argname: $argtype),*) $(-> $rettype)? {
161188
unsafe {
162-
let func = load_from_module(Module::new($module));
189+
let func = load_from_module();
163190
func($($argname),*)
164191
}
165192
}
166193

167-
fn load_from_module(module: Option<Module>) -> F {
194+
fn load_from_module() -> F {
168195
unsafe {
169196
static SYMBOL_NAME: &CStr = ansi_str!(sym $symbol);
170-
if let Some(f) = module.and_then(|m| m.proc_address(SYMBOL_NAME)) {
197+
198+
let f = crate::sys::compat::load_from_module(
199+
$name,
200+
SYMBOL_NAME,
201+
$load,
202+
$unicows
203+
);
204+
205+
if let Some(f) = f {
171206
PTR.store(f.as_ptr(), Ordering::Relaxed);
172207
mem::transmute(f)
173208
} else {
@@ -177,13 +212,27 @@ macro_rules! compat_fn_with_fallback {
177212
}
178213
}
179214

215+
#[allow(dead_code)]
216+
pub fn available() -> Option<F> {
217+
let mut ptr = PTR.load(Ordering::Relaxed);
218+
if ptr == load as *mut _ {
219+
ptr = load_from_module() as *mut _;
220+
}
221+
222+
if ptr != fallback as *mut _ {
223+
Some(unsafe { mem::transmute(ptr) })
224+
} else {
225+
None
226+
}
227+
}
228+
180229
#[allow(unused_variables)]
181-
unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype {
230+
unsafe extern "system" fn fallback($($argname: $argtype),*) $(-> $rettype)? {
182231
$fallback_body
183232
}
184233

185234
#[inline(always)]
186-
pub unsafe fn call($($argname: $argtype),*) -> $rettype {
235+
pub unsafe fn call($($argname: $argtype),*) $(-> $rettype)? {
187236
unsafe {
188237
let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
189238
func($($argname),*)
@@ -193,7 +242,8 @@ macro_rules! compat_fn_with_fallback {
193242
#[allow(unused)]
194243
$(#[$meta])*
195244
$vis use $symbol::call as $symbol;
196-
)*)
245+
)*
246+
}
197247
}
198248

199249
/// Optionally loaded functions.
@@ -203,7 +253,7 @@ macro_rules! compat_fn_with_fallback {
203253
macro_rules! compat_fn_optional {
204254
($(
205255
$(#[$meta:meta])*
206-
$vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?;
256+
$vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),* $(,)?) $(-> $rettype:ty)?;
207257
)+) => (
208258
$(
209259
pub mod $symbol {
@@ -219,8 +269,19 @@ macro_rules! compat_fn_optional {
219269
type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?;
220270

221271
#[inline(always)]
272+
#[allow(dead_code)]
222273
pub fn option() -> Option<F> {
223-
NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) })
274+
unsafe {
275+
NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) })
276+
}
277+
}
278+
279+
#[inline(always)]
280+
#[allow(dead_code)]
281+
pub unsafe fn call($($argname: $argtype),*) $(-> $rettype)? {
282+
unsafe {
283+
(mem::transmute::<_, F>(PTR.load(Ordering::Relaxed)))($($argname),*)
284+
}
224285
}
225286
}
226287
#[inline]
@@ -231,6 +292,28 @@ macro_rules! compat_fn_optional {
231292
)
232293
}
233294

295+
pub(crate) fn load_from_module(
296+
module_name: &CStr,
297+
symbol_name: &CStr,
298+
load: bool,
299+
unicows: bool,
300+
) -> Option<NonNull<c_void>> {
301+
let in_unicows = if unicows {
302+
unsafe { Module::new(UNICOWS).and_then(|m| m.proc_address(symbol_name)) }
303+
} else {
304+
None
305+
};
306+
307+
in_unicows.or_else(|| {
308+
if load {
309+
unsafe { Module::new(module_name) }
310+
} else {
311+
unsafe { Module::load(module_name) }
312+
}
313+
.and_then(|m| m.proc_address(symbol_name))
314+
})
315+
}
316+
234317
/// Load all needed functions from "api-ms-win-core-synch-l1-2-0".
235318
#[cfg(target_vendor = "win7")]
236319
pub(super) fn load_synch_functions() {
@@ -250,6 +333,4 @@ pub(super) fn load_synch_functions() {
250333
c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Relaxed);
251334
Some(())
252335
}
253-
254-
try_load();
255336
}

0 commit comments

Comments
 (0)