12
12
//! function is available but afterwards it's just a load and a jump.
13
13
14
14
use crate :: ffi:: CString ;
15
- use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
16
15
use crate :: sys:: c;
17
16
18
17
pub fn lookup ( module : & str , symbol : & str ) -> Option < usize > {
@@ -28,45 +27,53 @@ pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
28
27
}
29
28
}
30
29
31
- pub fn store_func ( ptr : & AtomicUsize , module : & str , symbol : & str , fallback : usize ) -> usize {
32
- let value = lookup ( module, symbol) . unwrap_or ( fallback) ;
33
- ptr. store ( value, Ordering :: SeqCst ) ;
34
- value
35
- }
36
-
37
30
macro_rules! compat_fn {
38
- ( $module: ident : $(
31
+ ( $module: literal : $(
39
32
$( #[ $meta: meta] ) *
40
- pub fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* )
41
- -> $rettype: ty {
42
- $( $body: expr) ;*
43
- }
33
+ pub fn $symbol: ident( $( $argname: ident: $argtype: ty) ,* ) -> $rettype: ty $body: block
44
34
) * ) => ( $(
45
- #[ allow( unused_variables) ]
46
35
$( #[ $meta] ) *
47
- pub unsafe fn $symbol( $( $argname: $argtype) ,* ) -> $rettype {
36
+ pub mod $symbol {
37
+ use super :: * ;
48
38
use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
49
39
use crate :: mem;
50
- type F = unsafe extern "system" fn ( $( $argtype) ,* ) -> $rettype;
51
40
52
41
static PTR : AtomicUsize = AtomicUsize :: new( 0 ) ;
53
42
43
+ #[ allow( unused_variables) ]
44
+ unsafe extern "system" fn fallback( $( $argname: $argtype) ,* ) -> $rettype $body
45
+
46
+ #[ cold]
54
47
fn load( ) -> usize {
55
- crate :: sys:: compat:: store_func( & PTR ,
56
- stringify!( $module) ,
57
- stringify!( $symbol) ,
58
- fallback as usize )
48
+ // There is no locking here. It's okay if this is executed by multiple threads in
49
+ // parallel. `lookup` will result in the same value, and it's okay if they overwrite
50
+ // eachothers result as long as they do so atomically. We don't need any guarantees
51
+ // about memory ordering, as this involves just a single atomic variable which is
52
+ // not used to protect or order anything else.
53
+ let addr = crate :: sys:: compat:: lookup( $module, stringify!( $symbol) )
54
+ . unwrap_or( fallback as usize ) ;
55
+ PTR . store( addr, Ordering :: Relaxed ) ;
56
+ addr
59
57
}
60
- unsafe extern "system" fn fallback( $( $argname: $argtype) ,* )
61
- -> $rettype {
62
- $( $body) ;*
58
+
59
+ fn addr( ) -> usize {
60
+ match PTR . load( Ordering :: Relaxed ) {
61
+ 0 => load( ) ,
62
+ addr => addr,
63
+ }
63
64
}
64
65
65
- let addr = match PTR . load( Ordering :: SeqCst ) {
66
- 0 => load( ) ,
67
- n => n,
68
- } ;
69
- mem:: transmute:: <usize , F >( addr) ( $( $argname) ,* )
66
+ #[ allow( dead_code) ]
67
+ pub fn is_available( ) -> bool {
68
+ addr( ) != fallback as usize
69
+ }
70
+
71
+ pub unsafe fn call( $( $argname: $argtype) ,* ) -> $rettype {
72
+ type F = unsafe extern "system" fn ( $( $argtype) ,* ) -> $rettype;
73
+ mem:: transmute:: <usize , F >( addr( ) ) ( $( $argname) ,* )
74
+ }
70
75
}
76
+
77
+ pub use $symbol:: call as $symbol;
71
78
) * )
72
79
}
0 commit comments