@@ -115,6 +115,13 @@ impl Module {
115
115
NonNull :: new ( module) . map ( Self )
116
116
}
117
117
118
+ #[ allow( dead_code) ]
119
+ pub unsafe fn load ( name : & CStr ) -> Option < Self > {
120
+ // SAFETY: A CStr is always null terminated.
121
+ let module = c:: LoadLibraryA ( name. as_ptr ( ) . cast :: < u8 > ( ) ) ;
122
+ NonNull :: new ( module) . map ( Self )
123
+ }
124
+
118
125
// Try to get the address of a function.
119
126
pub fn proc_address ( self , name : & CStr ) -> Option < NonNull < c_void > > {
120
127
unsafe {
@@ -128,24 +135,28 @@ impl Module {
128
135
}
129
136
}
130
137
138
+ pub static UNICOWS : & CStr = c"unicows" ;
139
+
131
140
/// Load a function or use a fallback implementation if that fails.
132
141
macro_rules! compat_fn_with_fallback {
133
- ( pub static $module: ident: & CStr = $name: expr; $(
134
- $( #[ $meta: meta] ) *
135
- $vis: vis fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* ) -> $rettype: ty $fallback_body: block
136
- ) * ) => (
137
- pub static $module: & CStr = $name;
142
+ {
143
+ pub static $module: ident: & CStr = $name: expr => { load: $load: expr, unicows: $unicows: expr } ;
144
+ $(
145
+ $( #[ $meta: meta] ) *
146
+ $vis: vis fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* $( , ) ?) $( -> $rettype: ty) ? $fallback_body: block
147
+ ) +
148
+ } => {
138
149
$(
139
150
$( #[ $meta] ) *
140
151
pub mod $symbol {
141
152
#[ allow( unused_imports) ]
142
153
use super :: * ;
143
154
use crate :: mem;
144
- use crate :: ffi:: CStr ;
155
+ use crate :: ffi:: { CStr , c_void } ;
145
156
use crate :: sync:: atomic:: { AtomicPtr , Ordering } ;
146
- use crate :: sys:: compat:: Module ;
157
+ use crate :: sys:: compat:: { Module , UNICOWS } ;
147
158
148
- type F = unsafe extern "system" fn ( $( $argtype) ,* ) -> $rettype;
159
+ type F = unsafe extern "system" fn ( $( $argtype) ,* ) $ ( -> $rettype) ? ;
149
160
150
161
/// `PTR` contains a function pointer to one of three functions.
151
162
/// It starts with the `load` function.
@@ -154,15 +165,30 @@ macro_rules! compat_fn_with_fallback {
154
165
/// If it fails, then `PTR` is set to `fallback`.
155
166
static PTR : AtomicPtr <c_void> = AtomicPtr :: new( load as * mut _) ;
156
167
157
- unsafe extern "system" fn load( $( $argname: $argtype) ,* ) -> $rettype {
158
- let func = load_from_module( Module :: new ( $module ) ) ;
168
+ unsafe extern "system" fn load( $( $argname: $argtype) ,* ) $ ( -> $rettype) ? {
169
+ let func = load_from_module( ) ;
159
170
func( $( $argname) ,* )
160
171
}
161
172
162
- fn load_from_module( module : Option < Module > ) -> F {
173
+ fn load_from_module( ) -> F {
163
174
unsafe {
164
175
static SYMBOL_NAME : & CStr = ansi_str!( sym $symbol) ;
165
- if let Some ( f) = module. and_then( |m| m. proc_address( SYMBOL_NAME ) ) {
176
+
177
+ let in_unicows = if $unicows {
178
+ Module :: new( UNICOWS ) . and_then( |m| m. proc_address( SYMBOL_NAME ) )
179
+ } else {
180
+ None
181
+ } ;
182
+
183
+ let f = in_unicows. or_else( || {
184
+ if $load {
185
+ Module :: new( $name)
186
+ } else {
187
+ Module :: load( $name)
188
+ } . and_then( |m| m. proc_address( SYMBOL_NAME ) )
189
+ } ) ;
190
+
191
+ if let Some ( f) = f {
166
192
PTR . store( f. as_ptr( ) , Ordering :: Relaxed ) ;
167
193
mem:: transmute( f)
168
194
} else {
@@ -172,20 +198,31 @@ macro_rules! compat_fn_with_fallback {
172
198
}
173
199
}
174
200
201
+ #[ allow( dead_code) ]
202
+ pub fn available( ) -> bool {
203
+ let mut ptr = PTR . load( Ordering :: Relaxed ) ;
204
+ if ptr == load as * mut _ {
205
+ ptr = load_from_module( ) as * mut _;
206
+ }
207
+
208
+ ptr != fallback as * mut _
209
+ }
210
+
175
211
#[ allow( unused_variables) ]
176
- unsafe extern "system" fn fallback( $( $argname: $argtype) ,* ) -> $rettype {
212
+ unsafe extern "system" fn fallback( $( $argname: $argtype) ,* ) $ ( -> $rettype) ? {
177
213
$fallback_body
178
214
}
179
215
180
216
#[ inline( always) ]
181
- pub unsafe fn call( $( $argname: $argtype) ,* ) -> $rettype {
217
+ pub unsafe fn call( $( $argname: $argtype) ,* ) $ ( -> $rettype) ? {
182
218
let func: F = mem:: transmute( PTR . load( Ordering :: Relaxed ) ) ;
183
219
func( $( $argname) ,* )
184
220
}
185
221
}
186
222
$( #[ $meta] ) *
187
223
$vis use $symbol:: call as $symbol;
188
- ) * )
224
+ ) *
225
+ }
189
226
}
190
227
191
228
/// Optionally loaded functions.
@@ -195,7 +232,7 @@ macro_rules! compat_fn_optional {
195
232
( $load_functions: expr;
196
233
$(
197
234
$( #[ $meta: meta] ) *
198
- $vis: vis fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* ) $( -> $rettype: ty) ?;
235
+ $vis: vis fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* $ ( , ) ? ) $( -> $rettype: ty) ?;
199
236
) +) => (
200
237
$(
201
238
pub mod $symbol {
@@ -211,32 +248,136 @@ macro_rules! compat_fn_optional {
211
248
type F = unsafe extern "system" fn ( $( $argtype) ,* ) $( -> $rettype) ?;
212
249
213
250
#[ inline( always) ]
251
+ #[ allow( dead_code) ]
214
252
pub fn option( ) -> Option <F > {
215
253
// Miri does not understand the way we do preloading
216
254
// therefore load the function here instead.
217
255
#[ cfg( miri) ] $load_functions;
218
256
NonNull :: new( PTR . load( Ordering :: Relaxed ) ) . map( |f| unsafe { mem:: transmute( f) } )
219
257
}
258
+
259
+ #[ inline( always) ]
260
+ #[ allow( dead_code) ]
261
+ pub unsafe fn call( $( $argname: $argtype) ,* ) $( -> $rettype) ? {
262
+ ( mem:: transmute:: <_, F >( PTR . load( Ordering :: Relaxed ) ) ) ( $( $argname) ,* )
263
+ }
220
264
}
265
+
266
+ #[ allow( unused_imports) ]
267
+ $( #[ $meta] ) *
268
+ $vis use $symbol:: call as $symbol;
221
269
) +
222
270
)
223
271
}
224
272
273
+ macro_rules! compat_fn_lazy {
274
+ {
275
+ pub static $module: ident: & CStr = $name: expr => { load: $load: expr, unicows: $unicows: expr } ;
276
+ $(
277
+ $( #[ $meta: meta] ) *
278
+ $vis: vis fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* $( , ) ?) $( -> $rettype: ty) ?;
279
+ ) +
280
+ } => {
281
+ $(
282
+ $( #[ $meta] ) *
283
+ pub mod $symbol {
284
+ #[ allow( unused_imports) ]
285
+ use super :: * ;
286
+ use crate :: mem;
287
+ use crate :: ffi:: { CStr , c_void} ;
288
+ use crate :: sync:: atomic:: { AtomicPtr , Ordering } ;
289
+ use crate :: sys:: compat:: { Module , UNICOWS } ;
290
+
291
+ type F = unsafe extern "system" fn ( $( $argtype) ,* ) $( -> $rettype) ?;
292
+
293
+ /// `PTR` contains a function pointer to one of three functions.
294
+ /// It starts with the `load` function.
295
+ /// When that is called it attempts to load the requested symbol.
296
+ /// If it succeeds, `PTR` is set to the address of that symbol.
297
+ /// If it fails, then `PTR` is set to `fallback`.
298
+ static PTR : AtomicPtr <c_void> = AtomicPtr :: new( load as * mut _) ;
299
+
300
+ unsafe extern "system" fn load( $( $argname: $argtype) ,* ) $( -> $rettype) ? {
301
+ let func = load_from_module( ) ;
302
+ ( func. unwrap( ) ) ( $( $argname) ,* )
303
+ }
304
+
305
+ fn load_from_module( ) -> Option <F > {
306
+ unsafe {
307
+ static SYMBOL_NAME : & CStr = ansi_str!( sym $symbol) ;
308
+
309
+ let in_unicows = if $unicows {
310
+ Module :: new( UNICOWS ) . and_then( |m| m. proc_address( SYMBOL_NAME ) )
311
+ } else {
312
+ None
313
+ } ;
314
+
315
+ let f = in_unicows. or_else( || {
316
+ if $load {
317
+ Module :: new( $name)
318
+ } else {
319
+ Module :: load( $name)
320
+ } . and_then( |m| m. proc_address( SYMBOL_NAME ) )
321
+ } ) ;
322
+
323
+ if let Some ( f) = f {
324
+ PTR . store( f. as_ptr( ) , Ordering :: Relaxed ) ;
325
+ Some ( mem:: transmute( f) )
326
+ } else {
327
+ PTR . store( crate :: ptr:: null_mut( ) , Ordering :: Relaxed ) ;
328
+ None
329
+ }
330
+ }
331
+ }
332
+
333
+ #[ allow( dead_code) ]
334
+ pub fn option( ) -> Option <F > {
335
+ unsafe {
336
+ let ptr = PTR . load( Ordering :: Relaxed ) ;
337
+ if ptr == load as * mut _ {
338
+ load_from_module( )
339
+ } else {
340
+ Some ( mem:: transmute( ptr) )
341
+ }
342
+ }
343
+ }
344
+
345
+ #[ inline( always) ]
346
+ pub unsafe fn call( $( $argname: $argtype) ,* ) $( -> $rettype) ? {
347
+ let func: F = mem:: transmute( PTR . load( Ordering :: Relaxed ) ) ;
348
+ func( $( $argname) ,* )
349
+ }
350
+ }
351
+ $( #[ $meta] ) *
352
+ $vis use $symbol:: call as $symbol;
353
+ ) *
354
+ }
355
+ }
356
+
357
+ macro_rules! static_load {
358
+ (
359
+ $library: expr,
360
+ [ $( $symbol: ident) ,* $( , ) ?]
361
+ ) => {
362
+ $(
363
+ let $symbol = $library. proc_address( ansi_str!( sym $symbol) ) ?;
364
+ ) *
365
+ $(
366
+ c:: $symbol:: PTR . store( $symbol. as_ptr( ) , Ordering :: Relaxed ) ;
367
+ ) *
368
+ }
369
+ }
370
+
225
371
/// Load all needed functions from "api-ms-win-core-synch-l1-2-0".
226
372
pub ( super ) fn load_synch_functions ( ) {
227
373
fn try_load ( ) -> Option < ( ) > {
228
374
const MODULE_NAME : & CStr = c"api-ms-win-core-synch-l1-2-0" ;
229
- const WAIT_ON_ADDRESS : & CStr = c"WaitOnAddress" ;
230
- const WAKE_BY_ADDRESS_SINGLE : & CStr = c"WakeByAddressSingle" ;
231
375
232
376
// Try loading the library and all the required functions.
233
377
// If any step fails, then they all fail.
234
378
let library = unsafe { Module :: new ( MODULE_NAME ) } ?;
235
- let wait_on_address = library. proc_address ( WAIT_ON_ADDRESS ) ?;
236
- let wake_by_address_single = library. proc_address ( WAKE_BY_ADDRESS_SINGLE ) ?;
379
+ static_load ! ( library, [ WaitOnAddress , WakeByAddressSingle ] ) ;
237
380
238
- c:: WaitOnAddress :: PTR . store ( wait_on_address. as_ptr ( ) , Ordering :: Relaxed ) ;
239
- c:: WakeByAddressSingle :: PTR . store ( wake_by_address_single. as_ptr ( ) , Ordering :: Relaxed ) ;
240
381
Some ( ( ) )
241
382
}
242
383
0 commit comments