当动态加载库的生命周期到期时,如何修复段错误?

时间:2016-02-24 14:00:13

标签: shared-libraries rust ffi

我使用以下方案:

  1. 启动主程序。
  2. 动态加载/卸载必要的库,而不会中断主程序。
  3. 主程序终止。
  4. 所有代码(主程序,动态库)都是用Rust编写的,它都是用-Cprefer-dynamic编译的。

    动态库包含一个Plugin结构,它使用plugin::Plugin函数实现new特征,该函数返回一个盒装特征对象(plugin::Plugin)。

    动态库示例:

    #[derive(Debug)]
    pub struct Plugin;
    
    impl Plugin {
        #[no_mangle]
        pub fn new() -> Box<plugin::Plugin> {
            println!("IN NEW!");
            Box::new(Plugin)
        }
    }
    
    impl plugin::Plugin for Plugin {
        fn test(&mut self) -> plugin::Result<()> {
            println!("IN TEST!");
            Ok(())
        }
    }
    

    plugin::Plugin是一个特质:

    pub trait Plugin: Debug {
        fn test(&mut self) -> Result<()>;
    }
    

    主程序:

    fn main() {
        env_logger::init().unwrap();
        info!("[MAIN]<-");
    
        if let Ok(mut plugins) = load(Path::new("plugins/")) {
            for (path, plugin) in plugins.iter_mut() {
                debug!("path: {:?}, plugin: {:?}", path, plugin);
                plugin.plugin.test();
            }
            thread::sleep(Duration::from_secs(30));
            // <- as soon as the plugins is beyond his lifetime, segmentation fault.
        }
    
        info!("[MAIN]->");
    }
    
    fn load(path: & Path) -> Result<HashMap<String, Plugin>> {
        let mut plugins = HashMap::new();
    
        let valid_extensions: [& OsStr; 3] = ["dylib".as_ref(), "so".as_ref(), "dll".as_ref()];
        for dir_entry in try!(path.read_dir()) {
            let path = try!(dir_entry).path();
            if path.extension().is_none() || !valid_extensions.contains(& path.extension().unwrap()) {
                warn!("invalid dynamic library extension; extension: {:?}", path.extension());
                continue
            }
            let key = path.clone().into_os_string().into_string().unwrap();
    
            let lib = DynamicLibrary::open(Some(& path)).unwrap();
            let new: extern fn() -> Box<plugin::Plugin> = unsafe {
                std::mem::transmute(lib.symbol::<u8>("new").unwrap())
            };
    
            let plugin = Plugin {
                _lib: lib,
                plugin: new(),
            };
    
            plugins.insert(key.clone(), plugin);
        }
    
        Ok(plugins)
    }
    
    struct Plugin {
        _lib: DynamicLibrary,
        pub plugin: Box<plugin::Plugin>,
    }
    

    将FFI用于此类Rust-Rust交互是否正确?

0 个答案:

没有答案