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
+278 -3
View File
@@ -11,12 +11,78 @@ dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.60.2",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "env_filter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.10.2"
@@ -30,6 +96,19 @@ dependencies = [
"termcolor",
]
[[package]]
name = "env_logger"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]]
name = "hermit-abi"
version = "0.5.2"
@@ -50,7 +129,37 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
"windows-sys 0.61.2",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "jiff"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
@@ -81,16 +190,55 @@ version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "pretty_env_logger"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c"
dependencies = [
"env_logger",
"env_logger 0.10.2",
"log",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.12.2"
@@ -120,6 +268,46 @@ version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.4.1"
@@ -129,10 +317,17 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unshell-module-load"
version = "0.1.0"
dependencies = [
"env_logger 0.11.8",
"libloading",
"log",
"pretty_env_logger",
@@ -147,13 +342,19 @@ dependencies = [
"log",
]
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys",
"windows-sys 0.61.2",
]
[[package]]
@@ -162,6 +363,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -170,3 +380,68 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
+2
View File
@@ -6,6 +6,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
env_logger = "0.11.8"
libloading = "0.8.9"
log = "0.4.28"
pretty_env_logger = "0.5.0"
@@ -20,3 +21,4 @@ codegen-units = 1
panic = "abort"
debug = false # Remove debug
# trim-paths="all"
# panic=immediate-abort
+6 -17
View File
@@ -1,15 +1,9 @@
// #![no]
use unshell_modules::{Manager, Module, ModuleError, module_interface};
#[macro_use]
extern crate log;
mod manager;
use std::sync::{Arc, Mutex};
use unshell_modules::{Module, ModuleError, module_interface};
use crate::manager::Manager;
// use unshell_modules::{Module, ModuleError, module_interface};
module_interface! {
Interface {
@@ -19,9 +13,8 @@ module_interface! {
}
}
// const modules: Arc<Mutex<Vec<Module>>> = Arc::new(Mutex::new(Vec::new()));
fn main() {
// Init the logger (This uses like 600MB of storage)
pretty_env_logger::init();
info!("Initalized");
@@ -31,15 +24,11 @@ fn main() {
let mut modules = Vec::new();
for arg in args.skip(1) {
info!("Loading module: {}", arg);
modules.push(Module::new(&arg)?)
}
let _manager = Manager::new(modules);
// for i in 1..args.len() {}
// let interface = module.get_interface::<Interface>()?;
// interface.test1();
Manager::run(modules);
// manager.join();
Ok(())
}() {
-31
View File
@@ -1,31 +0,0 @@
use unshell_modules::{ManagerInterface, Module};
pub struct Manager {
modules: Vec<Module>,
}
impl Manager {
pub fn new(modules: Vec<Module>) -> Self {
let this = Self { modules };
let interface = this.get_interface();
for module in &this.modules {
if let Ok(init) = module.get_symbol::<fn(ManagerInterface)>(b"init") {
init(interface.clone());
} else {
warn!("init not found");
}
}
this
}
pub fn get_interface(&self) -> ManagerInterface {
ManagerInterface::from_raw(Self::test123)
}
pub extern "C" fn test123() {
info!("Manager Test Sucsessfull!");
}
}
+42 -5
View File
@@ -2,11 +2,15 @@
#[macro_use]
extern crate log;
use std::thread::{self, Thread};
use std::{
sync::{Arc, Mutex},
thread::{self, JoinHandle},
time::Duration,
};
// pub use unshell_logger::setup_logger;
pub use unshell_modules::setup_logger;
use unshell_modules::{ManagerInterface, module_interface};
use unshell_modules::{Manager, ModuleRuntime, module_interface};
extern "C" fn test1() {
warn!("Test1 called");
@@ -31,7 +35,40 @@ pub fn interface() -> Interface {
Interface::from_raw(test1, test2, test3)
}
#[unsafe(no_mangle)]
pub fn init(interface: ManagerInterface) {
thread::spawn(|| {});
struct RuntimeTest {
thread_handle: JoinHandle<()>,
}
impl RuntimeTest {
pub fn new(manager: Arc<Mutex<Manager>>) -> RuntimeTest {
Self {
thread_handle: thread::spawn(move || {
thread::sleep(Duration::from_secs(2));
let manager_lock = manager.lock().unwrap();
manager_lock.test1234(111.1111);
drop(manager_lock);
}),
}
}
}
impl ModuleRuntime for RuntimeTest {
// fn init(&mut self) {}
fn is_running(&self) -> bool {
!self.thread_handle.is_finished()
}
fn kill(self: Box<Self>) {
if !self.thread_handle.is_finished() {
let _ = self.thread_handle.join();
}
// drop(self);
}
}
#[unsafe(no_mangle)]
pub fn init(manager: Arc<Mutex<Manager>>) -> Box<dyn ModuleRuntime> {
Box::new(RuntimeTest::new(manager))
}
+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");
}