diff options
Diffstat (limited to 'worker/src/compute_core.rs')
-rw-r--r-- | worker/src/compute_core.rs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/worker/src/compute_core.rs b/worker/src/compute_core.rs new file mode 100644 index 0000000..aec2a9d --- /dev/null +++ b/worker/src/compute_core.rs @@ -0,0 +1,80 @@ +use std::io; +use std::path::Path; +use std::ffi::c_void; +use libloading::{Library, Symbol}; +use static_assertions::assert_eq_size; +use dd_utils::error::*; + +pub const CORE_API_VERSION: i32 = 1; + +pub struct ComputeCore { + #[used] + library: Library, + // init: unsafe extern "C" fn(i32) -> i32, + run_job: unsafe extern "C" fn(u64, *mut c_void, *mut u64, *mut *mut c_void) -> i32, + free_outdata: unsafe extern "C" fn(u64, *mut c_void), +} + +impl ComputeCore { + pub fn load<P: AsRef<Path>>(lib_path: P) -> io::Result<Self> { + let lib_path = lib_path.as_ref(); + let lib_path = lib_path.canonicalize().map_err(|e| { + format!("Library '{}' does not exist", lib_path.display()).perror(e) + })?; + + let library = libloading::Library::new(&lib_path).map_err(|e| { + format!("Cannot load library at '{}'", lib_path.display()).perror(e) + })?; + + macro_rules! load_symbol { + ($name:expr, $symname:expr, $typ:ty) => {{ + let sym: io::Result<Symbol<$typ>> = library.get($symname).map_err(|e| { + format!("Failed to load symbol '{}' from library '{}'", $name, lib_path.display()).perror(e) + }); + sym.map(|s| std::mem::transmute::<*mut c_void, $typ>(s.into_raw().into_raw())) + }} + } + + let init = unsafe { load_symbol!("worker_init", b"worker_init\0", unsafe extern "C" fn(i32) -> i32)? }; + let run_job = unsafe { load_symbol!("worker_run_job",b"worker_run_job\0", unsafe extern "C" fn(u64, *mut c_void, *mut u64, *mut *mut c_void) -> i32)? }; + let free_outdata = unsafe { load_symbol!("worker_free_outdata", b"worker_free_outdata\0", unsafe extern "C" fn(u64, *mut c_void))? }; + + let ret = unsafe { + init(CORE_API_VERSION) + }; + if ret != 0 { + return Err(format!("Library refused initialisation at version {}: '{}'", CORE_API_VERSION, lib_path.display()).ioerr()); + } + + Ok(ComputeCore { library, /*init,*/ run_job, free_outdata }) + } + + /// Will block on this thread, so if you don't want to block, spawn a new thread. + /// This does not syntactically need mutability, but since one can only run one job at a time + /// on a core, semantic mutability seems warranted. + pub fn run_job(&mut self, input_data: &mut [u8]) -> (i32, Vec<u8>) { + let mut outsize = 0u64; + let mut outdataptr: *mut c_void = std::ptr::null_mut(); + + assert_eq_size!(u64, usize); + + let ret = unsafe { + (self.run_job)(input_data.len() as u64, input_data.as_mut_ptr() as *mut c_void, &mut outsize, &mut outdataptr) + }; + + let mut result = (ret, Vec::new()); + + if outsize != 0 && outdataptr != std::ptr::null_mut() { + result.1.resize(outsize as usize, 0u8); + unsafe { + std::ptr::copy(outdataptr as *const u8, result.1.as_mut_ptr(), outsize as usize); + } + } + + unsafe { + (self.free_outdata)(outsize, outdataptr); + } + + result + } +} |