1212//! function is available but afterwards it's just a load and a jump.
1313
1414use crate :: ffi:: CString ;
15- use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
1615use crate :: sys:: c;
1716
1817pub fn lookup ( module : & str , symbol : & str ) -> Option < usize > {
@@ -28,45 +27,53 @@ pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
2827 }
2928}
3029
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-
3730macro_rules! compat_fn {
38- ( $module: ident : $(
31+ ( $module: literal : $(
3932 $( #[ $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
4434 ) * ) => ( $(
45- #[ allow( unused_variables) ]
4635 $( #[ $meta] ) *
47- pub unsafe fn $symbol( $( $argname: $argtype) ,* ) -> $rettype {
36+ pub mod $symbol {
37+ use super :: * ;
4838 use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
4939 use crate :: mem;
50- type F = unsafe extern "system" fn ( $( $argtype) ,* ) -> $rettype;
5140
5241 static PTR : AtomicUsize = AtomicUsize :: new( 0 ) ;
5342
43+ #[ allow( unused_variables) ]
44+ unsafe extern "system" fn fallback( $( $argname: $argtype) ,* ) -> $rettype $body
45+
46+ #[ cold]
5447 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
5957 }
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+ }
6364 }
6465
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+ }
7075 }
76+
77+ pub use $symbol:: call as $symbol;
7178 ) * )
7279}
0 commit comments