From 68c9f084576ae406a6401cfea86293fc023a66e7 Mon Sep 17 00:00:00 2001 From: daniel-k Date: Wed, 6 Dec 2017 12:08:33 +0100 Subject: [PATCH] plugin: use Nifty Counter Idiom to intialize plugin list 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 --- fpga/include/villas/plugin.hpp | 23 ++++++++++++++++++++++- fpga/lib/plugin.cpp | 19 ++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/fpga/include/villas/plugin.hpp b/fpga/include/villas/plugin.hpp index 1691c15ff..b2ce41755 100644 --- a/fpga/include/villas/plugin.hpp +++ b/fpga/include/villas/plugin.hpp @@ -74,8 +74,29 @@ public: enum state state; 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; - static std::list pluginList; + 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 }; } // namespace villas diff --git a/fpga/lib/plugin.cpp b/fpga/lib/plugin.cpp index 309314da7..fd3c83494 100644 --- a/fpga/lib/plugin.cpp +++ b/fpga/lib/plugin.cpp @@ -25,7 +25,9 @@ #include #include -#include + +#include +#include #include "plugin.hpp" @@ -33,16 +35,27 @@ namespace villas { // list of all registered plugins -Plugin::PluginList Plugin::pluginList; +Plugin::PluginList& +Plugin::pluginList = reinterpret_cast(Plugin::pluginListBuffer); + +Plugin::PluginListBuffer +Plugin::pluginListBuffer; + +// relies on zero initialization +int Plugin::pluginListNiftyCounter; Plugin::Plugin() : + pluginType(Plugin::Type::Unknown), name(""), description(""), path(""), - pluginType(Plugin::Type::Unknown), state(STATE_INITIALIZED) { + // 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); }