1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
use cuda_base::cuda_function_declarations;
use std::ffi::CStr;
use std::mem;
use std::ptr;
use std::ptr::NonNull;
use std::{marker::PhantomData, os::raw::c_void};
use crate::os;
struct DynamicFn<T> {
pointer: usize,
_marker: PhantomData<T>,
}
impl<T> Default for DynamicFn<T> {
fn default() -> Self {
DynamicFn {
pointer: 0,
_marker: PhantomData,
}
}
}
impl<T> DynamicFn<T> {
unsafe fn get(&mut self, lib: *mut c_void, name: &[u8]) -> Option<T> {
match self.pointer {
0 => {
let addr = os::get_proc_address(lib, CStr::from_bytes_with_nul_unchecked(name));
if addr == ptr::null_mut() {
self.pointer = 1;
return None;
} else {
self.pointer = addr as _;
}
}
1 => return None,
_ => {}
}
Some(mem::transmute_copy(&self.pointer))
}
}
pub(crate) struct CudaDynamicFns {
lib_handle: NonNull<::std::ffi::c_void>,
fn_table: CudaFnTable,
}
impl CudaDynamicFns {
pub(crate) unsafe fn load_library(path: &str) -> Option<Self> {
let lib_handle = NonNull::new(os::load_library(path));
lib_handle.map(|lib_handle| CudaDynamicFns {
lib_handle,
fn_table: CudaFnTable::default(),
})
}
}
macro_rules! emit_cuda_fn_table {
($($abi:literal fn $fn_name:ident( $($arg_id:ident : $arg_type:ty),* ) -> $ret_type:ty;)*) => {
#[derive(Default)]
#[allow(improper_ctypes)]
#[allow(improper_ctypes_definitions)]
struct CudaFnTable {
$($fn_name: DynamicFn<extern $abi fn ( $($arg_id : $arg_type),* ) -> $ret_type>),*
}
impl CudaDynamicFns {
$(
#[allow(dead_code)]
pub(crate) fn $fn_name(&mut self, $($arg_id : $arg_type),*) -> Option<$ret_type> {
let func = unsafe { self.fn_table.$fn_name.get(self.lib_handle.as_ptr(), concat!(stringify!($fn_name), "\0").as_bytes()) };
func.map(|f| f($($arg_id),*) )
}
)*
}
};
}
cuda_function_declarations!(emit_cuda_fn_table);
|