diff --git a/common/include/villas/plugin.hpp b/common/include/villas/plugin.hpp index b3cb94738..4ddea0a5e 100644 --- a/common/include/villas/plugin.hpp +++ b/common/include/villas/plugin.hpp @@ -32,82 +32,106 @@ #include namespace villas { +namespace plugin { + +/* Forward declarations */ +class Plugin; + +template +using List = std::list; + +class Registry { + +protected: + static List<> *plugins; -class Plugin { public: - enum class Type { - Unknown, - FpgaIp, - FpgaCard, - Gpu - }; + static SpdLogger + getLogger() + { return loggerGetOrCreate("plugin:registry"); } - Plugin(Type type, const std::string& name); - virtual ~Plugin(); + static void dump(); - // copying a plugin doesn't make sense, so explicitly deny it - Plugin(Plugin const&) = delete; - void operator=(Plugin const&) = delete; + static void add(Plugin *p) + { + if (plugins == nullptr) + plugins = new List<>; - int load(); + plugins->push_back(p); + } + + static void remove(Plugin *p) + { + plugins->remove(p); + } + + template + static T * + lookup(const std::string &name) + { + for (Plugin *p : *plugins) { + T *t = dynamic_cast(p); + if (!t || t->name != name) + continue; + + return t; + } + + return nullptr; + } + + template + static List + lookup() + { + List list; + + for (Plugin *p : *plugins) { + T *t = dynamic_cast(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); +}; + +class Plugin { + + friend plugin::Registry; + +public: + Plugin(const std::string& name, const std::string &desc); + virtual ~Plugin(); + + // copying a plugin doesn't make sense, so explicitly deny it + Plugin(Plugin const&) = delete; + void operator=(Plugin const&) = delete; + virtual void dump(); - static void - dumpList(); + std::string getName(); + std::string getDescription(); - /// 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); - - /// Get all plugins of a given type. - static std::list - lookup(Type type); - - // TODO: check if this makes sense! (no intermediate plugins) - bool - operator==(const Plugin& other) const; - - Type pluginType; +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; - using PluginListBuffer = typename std::aligned_storage::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 diff --git a/common/lib/plugin.cpp b/common/lib/plugin.cpp index b2f27996c..2eb9bcff6 100644 --- a/common/lib/plugin.cpp +++ b/common/lib/plugin.cpp @@ -28,41 +28,23 @@ #include -namespace villas { +using namespace villas::plugin; -// list of all registered plugins -Plugin::PluginList& -Plugin::pluginList = reinterpret_cast(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::lookup(Plugin::Type type) +std::string Plugin::getDescription() { - std::list list; - for(auto& p : pluginList) { - if(p->pluginType == type) - list.push_back(p); - } - - return list; + return description; } - -bool -Plugin::operator==(const Plugin &other) const -{ - return (this->pluginType == other.pluginType) and (this->name == other.name); -} - -} // namespace villas