From 0a9b86edfadeb7ad75beda890a147b3b11d553f5 Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:49:47 -0700 Subject: [PATCH] Module runtimes, pass manager into modules. --- unshell-module-load/Cargo.lock | 281 ++++++++++++++++++++++++++++- unshell-module-load/Cargo.toml | 2 + unshell-module-load/src/main.rs | 23 +-- unshell-module-load/src/manager.rs | 31 ---- unshell-module-test/src/lib.rs | 47 ++++- unshell-modules/src/lib.rs | 48 +++-- unshell-modules/src/manager.rs | 74 ++++++++ unshell-modules/src/module.rs | 3 +- 8 files changed, 438 insertions(+), 71 deletions(-) delete mode 100644 unshell-module-load/src/manager.rs create mode 100644 unshell-modules/src/manager.rs diff --git a/unshell-module-load/Cargo.lock b/unshell-module-load/Cargo.lock index 17c89bd..8c1abd9 100644 --- a/unshell-module-load/Cargo.lock +++ b/unshell-module-load/Cargo.lock @@ -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" diff --git a/unshell-module-load/Cargo.toml b/unshell-module-load/Cargo.toml index 33b15a6..41159ac 100644 --- a/unshell-module-load/Cargo.toml +++ b/unshell-module-load/Cargo.toml @@ -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 diff --git a/unshell-module-load/src/main.rs b/unshell-module-load/src/main.rs index c8ced95..b1574d4 100644 --- a/unshell-module-load/src/main.rs +++ b/unshell-module-load/src/main.rs @@ -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>> = 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.test1(); + Manager::run(modules); + // manager.join(); Ok(()) }() { diff --git a/unshell-module-load/src/manager.rs b/unshell-module-load/src/manager.rs deleted file mode 100644 index e52a6fc..0000000 --- a/unshell-module-load/src/manager.rs +++ /dev/null @@ -1,31 +0,0 @@ -use unshell_modules::{ManagerInterface, Module}; - -pub struct Manager { - modules: Vec, -} - -impl Manager { - pub fn new(modules: Vec) -> Self { - let this = Self { modules }; - - let interface = this.get_interface(); - - for module in &this.modules { - if let Ok(init) = module.get_symbol::(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!"); - } -} diff --git a/unshell-module-test/src/lib.rs b/unshell-module-test/src/lib.rs index 3b1788f..71b3c82 100644 --- a/unshell-module-test/src/lib.rs +++ b/unshell-module-test/src/lib.rs @@ -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>) -> 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) { + if !self.thread_handle.is_finished() { + let _ = self.thread_handle.join(); + } + // drop(self); + } +} + +#[unsafe(no_mangle)] +pub fn init(manager: Arc>) -> Box { + Box::new(RuntimeTest::new(manager)) } diff --git a/unshell-modules/src/lib.rs b/unshell-modules/src/lib.rs index 75086f6..7fcd0cb 100644 --- a/unshell-modules/src/lib.rs +++ b/unshell-modules/src/lib.rs @@ -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); +} + +/// "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(); - } -} diff --git a/unshell-modules/src/manager.rs b/unshell-modules/src/manager.rs new file mode 100644 index 0000000..fdeec44 --- /dev/null +++ b/unshell-modules/src/manager.rs @@ -0,0 +1,74 @@ +use std::{ + sync::{Arc, Mutex}, + thread, + time::Duration, +}; + +use crate::{Module, ModuleRuntime}; + +pub struct Manager { + modules: Vec, +} + +static mut MANAGER_RUNTIME: Option>> = None; + +impl Manager { + /// Create Manager, and run initilization for each Module + #[allow(static_mut_refs)] + pub fn run<'a>(modules: Vec) { + 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::>) -> Box>(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>) { + // 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> { + unsafe { MANAGER_RUNTIME.clone().unwrap() } + } +} diff --git a/unshell-modules/src/module.rs b/unshell-modules/src/module.rs index 617fe20..24f01d2 100644 --- a/unshell-modules/src/module.rs +++ b/unshell-modules/src/module.rs @@ -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::(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"); }