aboutsummaryrefslogtreecommitdiff
path: root/worker/src/compute_core.rs
diff options
context:
space:
mode:
Diffstat (limited to 'worker/src/compute_core.rs')
-rw-r--r--worker/src/compute_core.rs80
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
+ }
+}