1 use std::marker;
2 use std::mem;
3 use std::sync::atomic::{AtomicUsize, Ordering};
4 
5 use libc;
6 
7 macro_rules! dlsym {
8     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
9         #[allow(bad_style)]
10         static $name: ::sys::unix::dlsym::DlSym<unsafe extern fn($($t),*) -> $ret> =
11             ::sys::unix::dlsym::DlSym {
12                 name: concat!(stringify!($name), "\0"),
13                 addr: ::std::sync::atomic::ATOMIC_USIZE_INIT,
14                 _marker: ::std::marker::PhantomData,
15             };
16     )
17 }
18 
19 pub struct DlSym<F> {
20     pub name: &'static str,
21     pub addr: AtomicUsize,
22     pub _marker: marker::PhantomData<F>,
23 }
24 
25 impl<F> DlSym<F> {
get(&self) -> Option<&F>26     pub fn get(&self) -> Option<&F> {
27         assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
28         unsafe {
29             if self.addr.load(Ordering::SeqCst) == 0 {
30                 self.addr.store(fetch(self.name), Ordering::SeqCst);
31             }
32             if self.addr.load(Ordering::SeqCst) == 1 {
33                 None
34             } else {
35                 mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
36             }
37         }
38     }
39 }
40 
fetch(name: &str) -> usize41 unsafe fn fetch(name: &str) -> usize {
42     assert_eq!(name.as_bytes()[name.len() - 1], 0);
43     match libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize {
44         0 => 1,
45         n => n,
46     }
47 }
48