Module runtimes, pass manager into modules.

This commit is contained in:
Michael Mikovsky
2025-11-06 15:49:47 -07:00
parent 3e0d927465
commit 0a9b86edfa
8 changed files with 438 additions and 71 deletions
+34 -14
View File
@@ -2,30 +2,63 @@
extern crate log;
mod logger;
mod manager;
mod module;
pub use logger::setup_logger;
pub use manager::Manager;
pub use module::Module;
///Generic error type for module-related operations.
#[derive(Debug)]
pub enum ModuleError {
LibLoadingError(libloading::Error),
LogError(log::SetLoggerError),
LinkError(String),
Error(String),
}
/// Trait for defining modules that have a runtime.
pub trait ModuleRuntime: Send {
/// Returns true if the module is running.
/// After returning false, the module will be dropped.
fn is_running(&self) -> bool;
/// Consumes the module, implementation should kill whatever is running.
fn kill(self: Box<Self>);
}
/// "Module Interface" helper macro that creates a struct with function pointers
/// Useful for defining and requiring modules' functions accross FFI boundry.
#[macro_export]
macro_rules! module_interface {
($interface_name:ident { $(fn $fn_name:ident($($arg:ident : $ty:ty),* $(,)?) $(-> $ret:ty)?);* $(;)? }) => {
($(#[$struct_meta:meta])* $interface_name:ident { $($(#[$fn_meta:meta])* fn $fn_name:ident $(<$($gen:ident),+ $(,)?>)?($($arg:ident : $ty:ty),* $(,)?) $(-> $ret:ty)? $(where $($where_clause:tt)*)?);* $(;)? }) => {
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
#[allow(improper_ctypes_definitions)]
$(#[$struct_meta])*
pub struct $interface_name {
$(
// This line will FAIL TO COMPILE if you use generics in the macro input.
// You MUST use concrete types like *mut c_void for "generic" data.
$fn_name: extern "C" fn($($ty),*) $(-> $ret)?,
)*
}
impl $interface_name {
$(
#[inline(always)]
$(#[$fn_meta])* // Propagate function attributes
// This is the fix for the `impl` block.
// It adds the captured generics and where-clause to the wrapper function.
pub fn $fn_name $(<$($gen),+>)? (&self, $($arg: $ty),*) $(-> $ret)?
$(where $($where_clause)*)?
{
(self.$fn_name)($($arg),*)
}
)*
/// Create from raw function pointers
///
/// # Safety
@@ -39,19 +72,6 @@ macro_rules! module_interface {
$($fn_name),*
}
}
$(
#[inline(always)]
pub fn $fn_name(&self, $($arg: $ty),*) $(-> $ret)? {
(self.$fn_name)($($arg),*)
}
)*
}
};
}
module_interface! {
ManagerInterface {
fn test123();
}
}
+74
View File
@@ -0,0 +1,74 @@
use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
};
use crate::{Module, ModuleRuntime};
pub struct Manager {
modules: Vec<Module>,
}
static mut MANAGER_RUNTIME: Option<Arc<Mutex<Manager>>> = None;
impl Manager {
/// Create Manager, and run initilization for each Module
#[allow(static_mut_refs)]
pub fn run<'a>(modules: Vec<Module>) {
let module_count = modules.len();
let this = Self { modules };
let this = Arc::new(Mutex::new(this));
let mut runtimes = Vec::new();
for i in 0..module_count {
info!("Initializing {}", i);
let this_lock = this.lock().unwrap();
let init = if let Ok(init) =
this_lock.modules[i]
.get_symbol::<fn(Arc<Mutex<Manager>>) -> Box<dyn ModuleRuntime>>(b"init")
{
init.to_owned()
} else {
warn!("init not found");
continue;
};
let runtime = init(this.clone());
runtimes.push(runtime);
}
Self::join(&mut runtimes);
}
// /// Helper function to retrieve ManagerInterface type, for interfacing with ModuleManager accross FFI boundry.
// pub fn get_interface(&self) -> ManagerInterface {
// ManagerInterface::from_raw(Self::get_manager)
// }
/// Iterateratively loop through all runtimes, until all are finished executing
pub fn join(runtimes: &mut Vec<Box<dyn ModuleRuntime>>) {
// let mut len = runtimes.len().clone();
while runtimes.len() > 0 {
runtimes.retain(|runtime| runtime.is_running());
thread::sleep(Duration::from_micros(100));
}
}
// pub extern "C" fn test123() {
// info!("Manager Test Sucsessfull!");
// }
pub extern "C" fn test1234(&self, float: f32) {
info!("Manager Test Sucsessfull! {}", float.powf(2.));
}
#[allow(static_mut_refs, improper_ctypes_definitions)]
pub extern "C" fn get_manager() -> Arc<Mutex<Manager>> {
unsafe { MANAGER_RUNTIME.clone().unwrap() }
}
}
+2 -1
View File
@@ -2,6 +2,7 @@ use libloading::{Library, Symbol};
use crate::{ModuleError, logger::SetupLogger};
// #[derive(Clone, Copy)]
pub struct Module {
// name: String,
lib: Library,
@@ -17,7 +18,7 @@ impl Module {
};
if let Ok(setup_logger) = this.get_symbol::<SetupLogger>(b"setup_logger") {
setup_logger(log::logger(), log::max_level()).unwrap();
setup_logger(log::logger(), log::max_level()).map_err(|e| ModuleError::LogError(e))?;
} else {
warn!("setup_logger not found");
}