Commit 2c11256c authored by Steffen Vogel's avatar Steffen Vogel 🎅🏼

plugin: rewrite

parent 1a956d7a
......@@ -32,82 +32,106 @@
#include <villas/common.h>
namespace villas {
namespace plugin {
class Plugin {
public:
/* Forward declarations */
class Plugin;
enum class Type {
Unknown,
FpgaIp,
FpgaCard,
Gpu
};
template<typename T = Plugin>
using List = std::list<T *>;
Plugin(Type type, const std::string& name);
virtual ~Plugin();
class Registry {
// copying a plugin doesn't make sense, so explicitly deny it
Plugin(Plugin const&) = delete;
void operator=(Plugin const&) = delete;
protected:
static List<> *plugins;
int load();
public:
static SpdLogger
getLogger()
{ return loggerGetOrCreate("plugin:registry"); }
static void dump();
static void add(Plugin *p)
{
if (plugins == nullptr)
plugins = new List<>;
plugins->push_back(p);
}
static void remove(Plugin *p)
{
plugins->remove(p);
}
template<typename T = Plugin>
static T *
lookup(const std::string &name)
{
for (Plugin *p : *plugins) {
T *t = dynamic_cast<T *>(p);
if (!t || t->name != name)
continue;
return t;
}
return nullptr;
}
template<typename T = Plugin>
static List<T>
lookup()
{
List<T> list;
for (Plugin *p : *plugins) {
T *t = dynamic_cast<T *>(p);
if (t)
list.push_back(t);
}
return list;
}
};
class Loader {
public:
int load(const std::string &path);
int unload();
virtual int parse(json_t *cfg);
virtual void dump();
};
static void
dumpList();
class Plugin {
/// Find plugin by type and (optional if empty) by name. If more match, it
/// is not defined which one will be returned.
static Plugin *
lookup(Type type, std::string name);
friend plugin::Registry;
/// Get all plugins of a given type.
static std::list<Plugin*>
lookup(Type type);
public:
Plugin(const std::string& name, const std::string &desc);
virtual ~Plugin();
// TODO: check if this makes sense! (no intermediate plugins)
bool
operator==(const Plugin& other) const;
// copying a plugin doesn't make sense, so explicitly deny it
Plugin(Plugin const&) = delete;
void operator=(Plugin const&) = delete;
Type pluginType;
virtual void dump();
std::string getName();
std::string getDescription();
protected:
std::string name;
std::string description;
std::string path;
void *handle;
enum state state;
protected:
static SpdLogger
getStaticLogger()
{ return loggerGetOrCreate("plugin"); }
private:
/* Just using a standard std::list<> to hold plugins is problematic, because
we want to push Plugins to the list from within each Plugin's constructor
that is executed during static initialization. Since the order of static
initialization is undefined in C++, it may happen that a Plugin
constructor is executed before the list could be initialized. Therefore,
we use the Nifty Counter Idiom [1] to initialize the list ourself before
the first usage.
In short:
- allocate a buffer for the list
- initialize list before first usage
- (complicatedly) declaring a buffer is neccessary in order to avoid
that the constructor of the static list is executed again
[1] https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter
*/
using PluginList = std::list<Plugin *>;
using PluginListBuffer = typename std::aligned_storage<sizeof (Plugin::PluginList), alignof (Plugin::PluginList)>::type;
static PluginListBuffer pluginListBuffer; ///< buffer to hold a PluginList
static PluginList& pluginList; ///< reference to pluginListBuffer
static int pluginListNiftyCounter; ///< track if pluginList has been initialized
SpdLogger
getLogger()
{ return loggerGetOrCreate("plugin:" + name); }
};
} // namespace plugin
} // namespace villas
......@@ -28,41 +28,23 @@
#include <villas/plugin.hpp>
namespace villas {
using namespace villas::plugin;
// list of all registered plugins
Plugin::PluginList&
Plugin::pluginList = reinterpret_cast<Plugin::PluginList&>(Plugin::pluginListBuffer);
List<> * Registry::plugins;
Plugin::PluginListBuffer
Plugin::pluginListBuffer;
// relies on zero initialization
int Plugin::pluginListNiftyCounter;
Plugin::Plugin(Type type, const std::string& name) :
pluginType(type),
Plugin::Plugin(const std::string& name, const std::string& desc) :
name(name),
description(""),
path(""),
state(STATE_INITIALIZED)
description(desc)
{
// see comment in plugin.hpp on why we need to do this (Nifty Counter Idiom)
if(pluginListNiftyCounter++ == 0)
new (&pluginList) PluginList;
// push to global plugin list
pluginList.push_back(this);
Registry::add(this);
}
Plugin::~Plugin()
{
// clean from global plugin list
pluginList.remove(this);
Registry::remove(this);
}
#if 0
int
Plugin::parse(json_t *cfg)
{
......@@ -109,52 +91,32 @@ Plugin::unload()
return 0;
}
#endif
void
Plugin::dump()
{
auto logger = getStaticLogger();
auto logger = Registry::getLogger();
logger->info("Name: '{}' Description: '{}'", name, description);
}
void
Plugin::dumpList()
Registry::dump()
{
auto logger = getStaticLogger();
auto logger = Registry::getLogger();
logger->info("Registered plugins:");
for(auto& p : pluginList) {
logger->info(" - {}", p->name);
for(auto p : *plugins) {
logger->info(" - {}", p->getName());
}
}
Plugin*
Plugin::lookup(Plugin::Type type, std::string name)
std::string Plugin::getName()
{
for(auto& p : pluginList) {
if(p->pluginType == type and (name.empty() or p->name == name))
return p;
}
return nullptr;
return name;
}
std::list<Plugin*>
Plugin::lookup(Plugin::Type type)
std::string Plugin::getDescription()
{
std::list<Plugin*> list;
for(auto& p : pluginList) {
if(p->pluginType == type)
list.push_back(p);
}
return list;
}
bool
Plugin::operator==(const Plugin &other) const
{
return (this->pluginType == other.pluginType) and (this->name == other.name);
return description;
}
} // namespace villas
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment