Skip to content

Commit

Permalink
unfinished
Browse files Browse the repository at this point in the history
  • Loading branch information
milyin committed Oct 5, 2023
1 parent 65f03e4 commit fd01a65
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 121 deletions.
43 changes: 25 additions & 18 deletions plugins/example-plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
//
#![recursion_limit = "256"]

use core::panic;
use futures::select;
use log::{debug, info};
use core::panic;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::{
Expand All @@ -30,35 +30,42 @@ use zenoh_result::{bail, ZResult};

// The struct implementing the ZenohPlugin and ZenohPlugin traits
pub struct ExamplePlugin {}
const PLUGIN: ExamplePlugin = ExamplePlugin {};

// declaration of the plugin's VTable for zenohd to find the plugin's functions to be called
zenoh_plugin_trait::declare_plugin!(ExamplePlugin);
// zenoh_plugin_trait::declare_plugin!(plugin, ZenohPlugin);

#[no_mangle]
fn get_plugin_loader_version() -> PluginLoaderVersion {
1
}

#[no_mangle]
fn get_plugin_compatibility() -> Compatibility {
ExamplePlugin::compatibility()
}

#[no_mangle]
fn get_plugin_trait() -> &'static dyn ZenohPlugin {
&PLUGIN
}

// A default selector for this example of storage plugin (in case the config doesn't set it)
// This plugin will subscribe to this selector and declare a queryable with this selector
const DEFAULT_SELECTOR: &str = "demo/example/**";

impl ZenohPlugin for ExamplePlugin {}
impl Plugin for ExamplePlugin {
type StartArgs = Runtime;
type RunningPlugin = zenoh::plugins::RunningPlugin;

impl ZenohPlugin for ExamplePlugin {
// A mandatory const to define, in case of the plugin is built as a standalone executable
const STATIC_NAME: &'static str = "example";
// const STATIC_NAME: &'static str = "example";

// The first operation called by zenohd on the plugin
fn start(name: &str, runtime: &Self::StartArgs) -> ZResult<Self::RunningPlugin> {

fn start(name: &str, runtime: &Runtime) -> ZResult<RunningPlugin> {
// panic!("panic");

#[cfg(feature="crashable")]
#[cfg(feature = "crashable")]
{
panic!("FOOOO!!!! : {}", runtime._dummy);
}
info!("example started");
println!("example started !");
panic!("example started !!");

let config = runtime.config.lock();
let self_cfg = config.plugin(name).unwrap().as_object().unwrap();
// get the plugin's config details from self_cfg Map (here the "storage-selector" property)
Expand Down Expand Up @@ -104,15 +111,15 @@ impl RunningPluginTrait for RunningPlugin {
let guard = zlock!(&self.0);
let name = guard.name.clone();
std::mem::drop(guard);
let plugin = self.clone();
let PLUGIN = self.clone();
Arc::new(move |path, old, new| {
const STORAGE_SELECTOR: &str = "storage-selector";
if path == STORAGE_SELECTOR || path.is_empty() {
match (old.get(STORAGE_SELECTOR), new.get(STORAGE_SELECTOR)) {
(Some(serde_json::Value::String(os)), Some(serde_json::Value::String(ns)))
if os == ns => {}
(_, Some(serde_json::Value::String(selector))) => {
let mut guard = zlock!(&plugin.0);
let mut guard = zlock!(&PLUGIN.0);
guard.flag.store(false, Relaxed);
guard.flag = Arc::new(AtomicBool::new(true));
match KeyExpr::try_from(selector.clone()) {
Expand All @@ -128,7 +135,7 @@ impl RunningPluginTrait for RunningPlugin {
return Ok(None);
}
(_, None) => {
let guard = zlock!(&plugin.0);
let guard = zlock!(&PLUGIN.0);
guard.flag.store(false, Relaxed);
}
_ => {
Expand Down
17 changes: 2 additions & 15 deletions plugins/zenoh-plugin-trait/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl Compatibility {
}
}
pub fn are_compatible(&self, other: &Self) -> bool {
RustVersion::are_compatible(&self.rust_version, &other.rust_version)
RustVersion::are_compatible(&self.rust_version, &other.rust_version)
&& self.struct_layouts.len() == other.struct_layouts.len()
&& self
.struct_layouts
Expand All @@ -112,18 +112,5 @@ impl Compatibility {
}

pub mod prelude {
pub use crate::{loading::*, vtable::*, Plugin, Validator};
}

pub trait PluginVTable {
fn compatibility() -> Compatibility;
}

pub trait Plugin: Sized + 'static {
type StartArgs: Validator;
type RunningPlugin;
/// Your plugins' default name when statically linked.
const STATIC_NAME: &'static str;
/// Starts your plugin. Use `Ok` to return your plugin's control structure
fn start(name: &str, args: &Self::StartArgs) -> ZResult<Self::RunningPlugin>;
pub use crate::vtable::*;
}
62 changes: 33 additions & 29 deletions plugins/zenoh-plugin-trait/src/loading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,12 @@ impl<StartArgs: 'static, RunningPlugin: 'static> PluginsManager<StartArgs, Runni
path,
match running_plugins.entry(name.into()) {
std::collections::hash_map::Entry::Occupied(_) => Ok(None),
std::collections::hash_map::Entry::Vacant(e) => {
// let compatible = match p.compatibility() {
// Some(c) => {
// if Compatibility::are_compatible(&compat, &c) {
// Ok(())
// } else {
// Err(zerror!("Plugin compatibility mismatch: host: {:?} - plugin: {:?}. This could lead to segfaults, so wer'e not starting it.", &compat, &c))
// }
// }
// None => Ok(()),
// };
// if let Err(e) = compatible {
// Err(e.into())
// } else {
match p.start(args) {
Ok(p) => Ok(Some(unsafe {
std::mem::transmute(&e.insert((path.into(), p)).1)
})),
Err(e) => Err(e),
}
}
std::collections::hash_map::Entry::Vacant(e) => match p.start(args) {
Ok(p) => Ok(Some(unsafe {
std::mem::transmute(&e.insert((path.into(), p)).1)
})),
Err(e) => Err(e),
},
},
)
})
Expand Down Expand Up @@ -170,11 +155,12 @@ impl<StartArgs: 'static, RunningPlugin: 'static> PluginsManager<StartArgs, Runni
lib: Library,
path: PathBuf,
) -> ZResult<DynamicPlugin<StartArgs, RunningPlugin>> {
DynamicPlugin::new(name.into(), lib, path).map_err(|e|
zerror!("Wrong PluginVTable version, your {} doesn't appear to be compatible with this version of Zenoh (vtable versions: plugin v{}, zenoh v{})",
name,
e.map_or_else(|| "UNKNWON".to_string(), |e| e.to_string()),
PLUGIN_VTABLE_VERSION).into()
DynamicPlugin::new(name.into(), lib, path).map_err(
|e| panic!("Incompatible plugin"), // TODO: fire zerror!
// zerror!("Wrong PluginVTable version, your {} doesn't appear to be compatible with this version of Zenoh (vtable versions: plugin v{}, zenoh v{})",
// name,
// e.map_or_else(|| "UNKNWON".to_string(), |e| e.to_string()),
// PLUGIN_VTABLE_VERSION).into()
)
}

Expand Down Expand Up @@ -266,15 +252,33 @@ impl<StartArgs, RunningPlugin> PluginStarter<StartArgs, RunningPlugin>
}
}

pub struct DynamicPlugin<StartArgs, RunningPlugin> {
pub struct DynamicPlugin<DynTraitPlugin> {
_lib: Library,
vtable: PluginVTable<StartArgs, RunningPlugin>,
vtable: Option<&DynTraitPlugin>,

Check failure on line 257 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-latest

missing lifetime specifier

Check failure on line 257 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS-latest

missing lifetime specifier

Check failure on line 257 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run tests on windows-latest

missing lifetime specifier
pub name: String,
pub path: PathBuf,
}

impl<StartArgs, RunningPlugin> DynamicPlugin<StartArgs, RunningPlugin> {
fn new(name: String, lib: Library, path: PathBuf) -> Result<Self, Option<PluginLoaderVersion>> {
fn new(name: String, lib: Library, path: PathBuf) -> ZResult<Self> {
// Check loader version
let get_plugin_loader_version =
unsafe { lib.get::<fn() -> PluginLoaderVersion>(b"get_plugin_loader_version") }?;
let plugin_loader_version = get_plugin_loader_version();
if plugin_loader_version != PLUGIN_LOADER_VERSION {
bail!(
"Plugin loader version mismatch: expected {}, got {}",
PLUGIN_LOADER_VERSION,
plugin_loader_version
);
}

// Check plugin compatibility. Matching loader versions guarantees that [`Compatibility`] structure is matching
let get_plugin_compatibility =
unsafe { lib.get::<fn() -> Compatibility>(b"get_plugin_compatibility") }?;
if get_plugin_compatibility().are_compatible(other)


let load_plugin = unsafe {

Check failure on line 282 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run checks on ubuntu-latest

expected `{`, found keyword `let`

Check failure on line 282 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-latest

expected `{`, found keyword `let`

Check failure on line 282 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run checks on macOS-latest

expected `{`, found keyword `let`

Check failure on line 282 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS-latest

expected `{`, found keyword `let`

Check failure on line 282 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run checks on windows-latest

expected `{`, found keyword `let`

Check failure on line 282 in plugins/zenoh-plugin-trait/src/loading.rs

View workflow job for this annotation

GitHub Actions / Run tests on windows-latest

expected `{`, found keyword `let`
lib.get::<fn(PluginLoaderVersion) -> LoadPluginResult<StartArgs, RunningPlugin>>(
b"load_plugin",
Expand Down
64 changes: 7 additions & 57 deletions plugins/zenoh-plugin-trait/src/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,80 +11,30 @@
// Contributors:
// ZettaScale Zenoh Team, <[email protected]>
//
use crate::*;
pub use no_mangle::*;
use zenoh_result::ZResult;


/// This number should change any time the [`Compatibility`] structure changes or plugin loading sequence changes
pub type PluginLoaderVersion = u64;
pub const PLUGIN_LOADER_VERSION: PluginLoaderVersion = 1;

type StartFn<StartArgs, RunningPlugin> = fn(&str, &StartArgs) -> ZResult<RunningPlugin>;

#[repr(C)]
struct PluginVTableInner<StartArgs, RunningPlugin> {
start: StartFn<StartArgs, RunningPlugin>,
}

/// Automagical padding such that [PluginVTable::init]'s result is the size of a cache line
#[repr(C)]
struct PluginVTablePadding {
__padding: [u8; PluginVTablePadding::padding_length()],
}
impl PluginVTablePadding {
const fn padding_length() -> usize {
64 - std::mem::size_of::<LoadPluginResultInner>()
}
fn new() -> Self {
PluginVTablePadding {
__padding: [0; Self::padding_length()],
}
}
}

#[repr(C)]
pub struct PluginVTable<StartArgs, RunningPlugin> {
inner: PluginVTableInner<StartArgs, RunningPlugin>,
padding: PluginVTablePadding,
}

impl<StartArgs, RunningPlugin> PluginVTable<StartArgs, RunningPlugin> {
pub fn new<ConcretePlugin: Plugin<StartArgs = StartArgs, RunningPlugin = RunningPlugin>>(
) -> Self {
PluginVTable {
inner: PluginVTableInner {
start: ConcretePlugin::start,
},
padding: PluginVTablePadding::new(),
}
}
pub fn start(&self, name: &str, start_args: &StartArgs) -> ZResult<RunningPlugin> {
(self.inner.start)(name, start_args)
}
}

pub use no_mangle::*;
#[cfg(feature = "no_mangle")]
pub mod no_mangle {
/// This macro will add a set of non-mangled functions for plugin loading if feature `no_mangle` is enabled (which it is by default).
#[macro_export]
macro_rules! declare_plugin {
($ty: path) => {
($ident: ident, $trait: item) => {
#[no_mangle]
fn get_plugin_loader_version() -> $crate::prelude::PluginVTableVersion {
fn get_plugin_loader_version() -> $crate::prelude::PluginLoaderVersion {
$crate::prelude::PLUGIN_LOADER_VERSION
}
#[no_mangle]
fn get_plugin_vtable_compatibility() -> $crate::Compatibility {
<<$ty as $crate::prelude::Plugin>::StartArgs as $crate::prelude::Validator>::compatibility()
fn get_plugin_compatibility() -> $crate::Compatibility {
<$item as $trait>::compatibility()
}
#[no_mangle]
fn get_plugin_vtable() -> $crate::prelude::PluginVTable<
<$ty as $crate::prelude::Plugin>::StartArgs,
<$ty as $crate::prelude::Plugin>::RunningPlugin,
> {
$crate::prelude::PluginVTable::new::<$ty>()
fn get_plugin_trait() -> &'static dyn $trait {
&$ident as &dyn $trait
}
};
}
Expand All @@ -93,6 +43,6 @@ pub mod no_mangle {
pub mod no_mangle {
#[macro_export]
macro_rules! declare_plugin {
($ty: path) => {};
($ident: ident, $trait: item) => {};
}
}
9 changes: 7 additions & 2 deletions zenoh/src/plugins/sealed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ zconfigurable! {
}

/// Zenoh plugins should implement this trait to ensure type-safety, even if the starting arguments and expected plugin types change in a future release.
pub trait ZenohPlugin: Plugin<StartArgs = StartArgs, RunningPlugin = RunningPlugin> {}
pub trait ZenohPlugin {
fn compatibility() -> Compatibility {
Compatibility::new(&[])
}
fn start(name: &str, args: &StartArgs) -> ZResult<RunningPlugin>;
}

/// A zenoh plugin receives a reference to a value of this type when started.
pub type StartArgs = Runtime;
Expand Down Expand Up @@ -70,8 +75,8 @@ pub trait RunningPluginTrait: Send + Sync + std::any::Any {
/// The zenoh plugins manager. It handles the full lifetime of plugins, from loading to destruction.
pub type PluginsManager = zenoh_plugin_trait::loading::PluginsManager<StartArgs, RunningPlugin>;

pub use zenoh_plugin_trait::Plugin;
pub use zenoh_plugin_trait::Compatibility;
pub use zenoh_plugin_trait::Plugin;
pub use zenoh_plugin_trait::Validator;
pub type ValidationFunction = std::sync::Arc<
dyn Fn(
Expand Down

0 comments on commit fd01a65

Please sign in to comment.