$darkmode
cloe::Plugin Class Reference

Public Member Functions

 Plugin (const std::string &plugin_path, const std::string &name="")
 
 Plugin (const PluginManifest &m, std::function< ModelFactory *()> fn, const std::string &name="")
 
std::string path () const
 
std::string name () const
 
std::string type () const
 
std::string type_version () const
 
std::string required_type_version () const
 
Schema schema () const
 
bool is_builtin () const
 
bool is_type_known () const
 
bool is_compatible () const
 
template<typename F >
std::unique_ptr< F > make () const
 

Friends

void to_json (Json &j, const Plugin &p)
 

Constructor & Destructor Documentation

◆ Plugin() [1/2]

cloe::Plugin::Plugin ( const std::string &  plugin_path,
const std::string &  name = "" 
)
explicit

Construct a Plugin by loading a dynamic library from disk.

The following call is used to load the plugin:

dlopen(plugin_path, RTLD_GLOBAL | RTLD_DEEPBIND | RTLD_NOW)

Discussion

Currently, this opens a plugin with the dlopen() call (provided by glibc). This constrains official support to Linux.

There are several ways we can open a plugin. Ideally, we would use:

dlmopen(LM_ID_NEWLM, plugin_path, RTLD_GLOBAL | RTLD_NOW)

This would open each plugin within its own namespace, which prevents one plugin from affecting another plugin. However, glibc does not support the use of the RTLD_GLOBAL mode in dlmopen(), and there is currently only support for up to 16 namespaces. See the following RFC:

RFC: Treat RTLD_GLOBAL as unique to namespace when used with dlmopen https://patchwork.ozlabs.org/project/glibc/patch/55A73673.3060104@redhat.com/

Unfortunately, this RFC hasn't seen much activity since 2015, so it is unlikely to merged soon, and even if it was, we wouldn't be able to use it until all platforms and distributions we support have that version.

The alternative to using dlmopen() is to use the non-namespaced dlopen():

dlopen(plugin_path, RTLD_LOCAL | RTLD_NOW)

With the local scope as achieved with RTLD_LOCAL, we prevent plugins from interfering with each other, but there is still a major problem with this approach: dependencies of a plugin are prevented from sharing symbols, which leads to runtime errors. Fixing this requires RTLD_GLOBAL:

dlopen(plugin_path, RTLD_GLOBAL | RTLD_NOW)

This causes problems combining plugins that include conflicting versions of libraries though, so we need to add the RTLD_DEEPLINK flag to cause libraries to prefer local symbols during resolution.

Note: The use of RTLD_NOW as opposed to RTLD_LAZY makes loader errors occur when we load the plugin as opposed to when the plugin is invoked. This comes at a performance penalty as all plugins will be loaded regardless of whether they are used. However, this moves errors to a point before a simulation occurs, which is preferable. In the future, we may lazily load plugins and then load them again once it is clear they will partake in the simulation.

◆ Plugin() [2/2]

cloe::Plugin::Plugin ( const PluginManifest m,
std::function< ModelFactory *()>  fn,
const std::string &  name = "" 
)

Construct a Plugin from a Plugin-compatible type itself.

This does not involve dlopen().

Member Function Documentation

◆ is_builtin()

bool cloe::Plugin::is_builtin ( ) const

Return whether this plugin is builtin (as opposed to loaded from disk).

◆ is_compatible()

bool cloe::Plugin::is_compatible ( ) const

Return whether this plugin is compatible with Cloe.

This should be checked before creating any objects with the factory function from the plugin. Deviation results in undefined behavior.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_type_known()

bool cloe::Plugin::is_type_known ( ) const

Return whether this plugin type is known to Cloe.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make()

template<typename F >
std::unique_ptr<F> cloe::Plugin::make ( ) const
inline

Attempt to cast this component to a sub-type.

  • Throws an exception if the component cannot be cast.
Here is the call graph for this function:

◆ name()

std::string cloe::Plugin::name ( ) const
inline

Return the given or intrinsic name of the plugin.

Here is the caller graph for this function:

◆ path()

std::string cloe::Plugin::path ( ) const
inline

Return the path to the loaded dynamic library.

  • Response may be empty if plugin is built-in.
Here is the caller graph for this function:

◆ required_type_version()

std::string cloe::Plugin::required_type_version ( ) const

Return the version that the Cloe library expects the plugin to have.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ schema()

Schema cloe::Plugin::schema ( ) const

Return the schema of this plugin.

◆ type()

std::string cloe::Plugin::type ( ) const
inline

Return the plugin type.

Here is the caller graph for this function:

◆ type_version()

std::string cloe::Plugin::type_version ( ) const
inline

Return the API version of the plugin.

Here is the caller graph for this function:

The documentation for this class was generated from the following files: