]> granicus.if.org Git - icinga2/commitdiff
Make order for deferred initializers deterministic
authorGunnar Beutner <gunnar@beutner.name>
Wed, 18 Mar 2015 12:24:31 +0000 (13:24 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Wed, 18 Mar 2015 12:24:31 +0000 (13:24 +0100)
refs #8791

16 files changed:
icinga-app/icinga.cpp
lib/base/CMakeLists.txt
lib/base/application.cpp
lib/base/initialize.cpp
lib/base/initialize.hpp
lib/base/loader.cpp [new file with mode: 0644]
lib/base/loader.hpp [new file with mode: 0644]
lib/base/type.hpp
lib/base/utility.cpp
lib/base/utility.hpp
lib/cli/nodeupdateconfigcommand.cpp
lib/cli/repositoryobjectcommand.cpp
lib/cli/troubleshootcommand.cpp
lib/config/configcompiler.cpp
lib/config/configfragment.hpp
test/livestatus.cpp

index 0e8c5956033a1d33877a56205c9e26d55a1013d1..e06fb955574607e893503c07b4450141e5507c29 100644 (file)
@@ -25,6 +25,7 @@
 #include "base/logger.hpp"
 #include "base/timer.hpp"
 #include "base/utility.hpp"
+#include "base/loader.hpp"
 #include "base/exception.hpp"
 #include "base/convert.hpp"
 #include "base/scriptglobal.hpp"
@@ -175,7 +176,7 @@ int Main(void)
        LogSeverity logLevel = Logger::GetConsoleLogSeverity();
        Logger::SetConsoleLogSeverity(LogWarning);
 
-       Utility::LoadExtensionLibrary("cli");
+       Loader::LoadExtensionLibrary("cli");
 
        po::options_description visibleDesc("Global options");
 
@@ -292,7 +293,7 @@ int Main(void)
                if (vm.count("library")) {
                        BOOST_FOREACH(const String& libraryName, vm["library"].as<std::vector<std::string> >()) {
                                try {
-                                       (void) Utility::LoadExtensionLibrary(libraryName);
+                                       (void) Loader::LoadExtensionLibrary(libraryName);
                                } catch (const std::exception& ex) {
                                        Log(LogCritical, "icinga-app")
                                            <<  "Could not load library \"" << libraryName << "\": " << DiagnosticInformation(ex);
@@ -476,9 +477,9 @@ int Main(void)
                Logger::SetConsoleLogSeverity(LogWarning);
 
                if (vm.count("app"))
-                       Utility::LoadExtensionLibrary(vm["app"].as<std::string>());
+                       Loader::LoadExtensionLibrary(vm["app"].as<std::string>());
                else
-                       Utility::LoadExtensionLibrary("icinga");
+                       Loader::LoadExtensionLibrary("icinga");
 
                Logger::SetConsoleLogSeverity(logLevel);
 
index 0a880e2c3310ec46352ecc15848b51af427b4332..fb7cea75e96a4713467731c226e8c3185926a057 100644 (file)
@@ -25,7 +25,7 @@ mkclass_target(sysloglogger.ti sysloglogger.thpp)
 set(base_SOURCES
   application.cpp application-version.cpp application.thpp array.cpp array-script.cpp boolean.cpp boolean-script.cpp console.cpp context.cpp
   convert.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp
-  exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp json-script.cpp logger.cpp logger.thpp math-script.cpp
+  exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp json-script.cpp loader.cpp logger.cpp logger.thpp math-script.cpp
   netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp object-script.cpp primitivetype.cpp process.cpp
   ringbuffer.cpp scriptframe.cpp function.cpp function-script.cpp functionwrapper.cpp scriptglobal.cpp
   scriptutils.cpp serializer.cpp socket.cpp socketevents.cpp stacktrace.cpp
index dbb5d8dfcc936432b21b4ef04991e012670474f0..d04f9ac712e8b19ec749026d2f49e0225900b1d8 100644 (file)
@@ -24,6 +24,7 @@
 #include "base/exception.hpp"
 #include "base/objectlock.hpp"
 #include "base/utility.hpp"
+#include "base/loader.hpp"
 #include "base/debug.hpp"
 #include "base/type.hpp"
 #include "base/convert.hpp"
@@ -134,7 +135,7 @@ void Application::InitializeBase(void)
        }
 #endif /* _WIN32 */
 
-       Utility::ExecuteDeferredInitializers();
+       Loader::ExecuteDeferredInitializers();
 
        /* make sure the thread pool gets initialized */
        GetTP();
index 5cc4561b9b821fb59a8b525b3ea7b427a00f1ddd..2042fca8830ae45b4ca1ebde22356da0cfbf63ac 100644 (file)
  ******************************************************************************/
 
 #include "base/initialize.hpp"
-#include "base/utility.hpp"
+#include "base/loader.hpp"
 
 using namespace icinga;
 
-bool icinga::InitializeOnceHelper(void (*func)(void))
+bool icinga::InitializeOnceHelper(void (*func)(void), int priority)
 {
-       Utility::AddDeferredInitializer(func);
+       Loader::AddDeferredInitializer(func, priority);
        return true;
 }
 
index 62de192da9c7a6d272566346aafae5b68d24084e..4b7848af2471d5917a262973e8abc85de7fd345d 100644 (file)
 namespace icinga
 {
 
-I2_BASE_API bool InitializeOnceHelper(void (*func)(void));
+I2_BASE_API bool InitializeOnceHelper(void (*func)(void), int priority = 0);
 
-#define INITIALIZE_ONCE(func)                                                          \
-       namespace { namespace UNIQUE_NAME(io) {                                         \
-               I2_EXPORT bool l_InitializeOnce(icinga::InitializeOnceHelper(func));    \
+#define INITIALIZE_ONCE(func)                                                                  \
+       namespace { namespace UNIQUE_NAME(io) {                                                 \
+               I2_EXPORT bool l_InitializeOnce(icinga::InitializeOnceHelper(func));            \
        } }
 
+#define INITIALIZE_ONCE_WITH_PRIORITY(func, priority)                                          \
+       namespace { namespace UNIQUE_NAME(io) {                                                 \
+               I2_EXPORT bool l_InitializeOnce(icinga::InitializeOnceHelper(func, priority));  \
+       } }
 }
 
 #endif /* INITIALIZE_H */
diff --git a/lib/base/loader.cpp b/lib/base/loader.cpp
new file mode 100644 (file)
index 0000000..036c163
--- /dev/null
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "base/loader.hpp"
+#include "base/logger.hpp"
+#include <boost/foreach.hpp>
+
+using namespace icinga;
+
+/**
+ * Loads the specified library.
+ *
+ * @param library The name of the library.
+ */
+void Loader::LoadExtensionLibrary(const String& library)
+{
+       String path;
+#if defined(_WIN32)
+       path = library + ".dll";
+#elif defined(__APPLE__)
+       path = "lib" + library + ".dylib";
+#else /* __APPLE__ */
+       path = "lib" + library + ".so";
+#endif /* _WIN32 */
+
+       Log(LogInformation, "Utility")
+           << "Loading library '" << path << "'";
+
+#ifdef _WIN32
+       HMODULE hModule = LoadLibrary(path.CStr());
+
+       if (hModule == NULL) {
+               BOOST_THROW_EXCEPTION(win32_error()
+                   << boost::errinfo_api_function("LoadLibrary")
+                   << errinfo_win32_error(GetLastError())
+                   << boost::errinfo_file_name(path));
+       }
+#else /* _WIN32 */
+       void *hModule = dlopen(path.CStr(), RTLD_NOW | RTLD_GLOBAL);
+
+       if (hModule == NULL) {
+               BOOST_THROW_EXCEPTION(std::runtime_error("Could not load library '" + path + "': " + dlerror()));
+       }
+#endif /* _WIN32 */
+
+       ExecuteDeferredInitializers();
+}
+
+boost::thread_specific_ptr<std::priority_queue<DeferredInitializer> >& Loader::GetDeferredInitializers(void)
+{
+       static boost::thread_specific_ptr<std::priority_queue<DeferredInitializer> > initializers;
+       return initializers;
+}
+
+void Loader::ExecuteDeferredInitializers(void)
+{
+       if (!GetDeferredInitializers().get())
+               return;
+
+       while (!GetDeferredInitializers().get()->empty()) {
+               DeferredInitializer initializer = GetDeferredInitializers().get()->top();
+               GetDeferredInitializers().get()->pop();
+               initializer();
+       }
+}
+
+void Loader::AddDeferredInitializer(const boost::function<void(void)>& callback, int priority)
+{
+       if (!GetDeferredInitializers().get())
+               GetDeferredInitializers().reset(new std::priority_queue<DeferredInitializer>());
+
+       GetDeferredInitializers().get()->push(DeferredInitializer(callback, priority));
+}
+
diff --git a/lib/base/loader.hpp b/lib/base/loader.hpp
new file mode 100644 (file)
index 0000000..aef033c
--- /dev/null
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#ifndef LOADER_H
+#define LOADER_H
+
+#include "base/i2-base.hpp"
+#include "base/string.hpp"
+#include <boost/thread/tss.hpp>
+#include <boost/function.hpp>
+#include <queue>
+
+namespace icinga
+{
+
+struct DeferredInitializer
+{
+public:
+       DeferredInitializer(const boost::function<void (void)>& callback, int priority)
+           : m_Callback(callback), m_Priority(priority)
+       { }
+
+       inline bool operator<(const DeferredInitializer& other) const
+       {
+               return m_Priority < other.m_Priority;
+       }
+
+       inline void operator()(void)
+       {
+               m_Callback();
+       }
+
+private:
+       boost::function<void (void)> m_Callback;
+       int m_Priority;
+};
+
+/**
+ * Loader helper functions.
+ *
+ * @ingroup base
+ */
+class I2_BASE_API Loader
+{
+public:
+       static void LoadExtensionLibrary(const String& library);
+
+       static void AddDeferredInitializer(const boost::function<void(void)>& callback, int priority = 0);
+       static void ExecuteDeferredInitializers(void);
+
+private:
+       Loader(void);
+
+       static boost::thread_specific_ptr<std::priority_queue<DeferredInitializer> >& GetDeferredInitializers(void);
+
+};
+
+}
+
+#endif /* LOADER_H */
index d1b2adb2762f86f876900ad42e5cf7431ab138f2..1c123fb1b313ca75a733a3dd09515b64074a57cc 100644 (file)
@@ -126,7 +126,7 @@ class TypeImpl
                        icinga::Type::Register(t); \
                } \
                \
-               INITIALIZE_ONCE(RegisterType ## type); \
+               INITIALIZE_ONCE_WITH_PRIORITY(RegisterType ## type, 10); \
        } } \
        DEFINE_TYPE_INSTANCE(type)
 
index 5fdf254680ac6a3a1f2b8b389aac5dc3ca0a9213..dd240a64da39c0435c627f23b0a7c05edbe1bcd6 100644 (file)
@@ -291,72 +291,6 @@ void Utility::Sleep(double timeout)
 #endif /* _WIN32 */
 }
 
-/**
- * Loads the specified library.
- *
- * @param library The name of the library.
- */
-void Utility::LoadExtensionLibrary(const String& library)
-{
-       String path;
-#if defined(_WIN32)
-       path = library + ".dll";
-#elif defined(__APPLE__)
-       path = "lib" + library + ".dylib";
-#else /* __APPLE__ */
-       path = "lib" + library + ".so";
-#endif /* _WIN32 */
-
-       Log(LogInformation, "Utility")
-           << "Loading library '" << path << "'";
-
-#ifdef _WIN32
-       HMODULE hModule = LoadLibrary(path.CStr());
-
-       if (hModule == NULL) {
-               BOOST_THROW_EXCEPTION(win32_error()
-                   << boost::errinfo_api_function("LoadLibrary")
-                   << errinfo_win32_error(GetLastError())
-                   << boost::errinfo_file_name(path));
-       }
-#else /* _WIN32 */
-       void *hModule = dlopen(path.CStr(), RTLD_NOW | RTLD_GLOBAL);
-
-       if (hModule == NULL) {
-               BOOST_THROW_EXCEPTION(std::runtime_error("Could not load library '" + path + "': " + dlerror()));
-       }
-#endif /* _WIN32 */
-
-       ExecuteDeferredInitializers();
-}
-
-boost::thread_specific_ptr<std::vector<boost::function<void(void)> > >& Utility::GetDeferredInitializers(void)
-{
-       static boost::thread_specific_ptr<std::vector<boost::function<void(void)> > > initializers;
-       return initializers;
-}
-
-void Utility::ExecuteDeferredInitializers(void)
-{
-       if (!GetDeferredInitializers().get())
-               return;
-
-       BOOST_FOREACH(const boost::function<void(void)>& callback, *GetDeferredInitializers().get()) {
-               VERIFY(callback);
-               callback();
-       }
-
-       GetDeferredInitializers().reset();
-}
-
-void Utility::AddDeferredInitializer(const boost::function<void(void)>& callback)
-{
-       if (!GetDeferredInitializers().get())
-               GetDeferredInitializers().reset(new std::vector<boost::function<void(void)> >());
-
-       GetDeferredInitializers().get()->push_back(callback);
-}
-
 /**
  * Generates a new unique ID.
  *
index c1702193e6934b831ad3341f78147cfb2a4343ce..7c0e7db189264a57bf1072fe1ad653bc819043a5 100644 (file)
@@ -94,11 +94,6 @@ public:
        static String FormatDateTime(const char *format, double ts);
        static String FormatErrorNumber(int code);
 
-       static void LoadExtensionLibrary(const String& library);
-
-       static void AddDeferredInitializer(const boost::function<void(void)>& callback);
-       static void ExecuteDeferredInitializers(void);
-
 #ifndef _WIN32
        static void SetNonBlocking(int fd);
        static void SetCloExec(int fd);
@@ -139,8 +134,6 @@ private:
        static boost::thread_specific_ptr<String> m_ThreadName;
        static boost::thread_specific_ptr<unsigned int> m_RandSeed;
 
-       static boost::thread_specific_ptr<std::vector<boost::function<void(void)> > >& GetDeferredInitializers(void);
-
 };
 
 }
index 905f57858c313a0c34d208e8be0d7cdfea5e5fa5..71a7b889a390c56fecfa7e9c6a31b5267c65938a 100644 (file)
@@ -83,8 +83,6 @@ int NodeUpdateConfigCommand::Run(const boost::program_options::variables_map& vm
 
        NodeUtility::PrintNodes(std::cout);
 
-       Utility::LoadExtensionLibrary("icinga");
-
        /* cache all existing object configs only once and pass it to AddObject() */
        std::vector<String> object_paths = RepositoryUtility::GetObjects();
        /* cache all existing changes only once and pass it to AddObject() */
index e50b45faa13b4ed187e594c2ac31a9b4295b403c..4e480f145191ae49b418fae6a4181f712801c1c7 100644 (file)
@@ -108,7 +108,6 @@ void RepositoryObjectCommand::InitParameters(boost::program_options::options_des
 std::vector<String> RepositoryObjectCommand::GetPositionalSuggestions(const String& word) const
 {
        if (m_Command == RepositoryCommandAdd) {
-               Utility::LoadExtensionLibrary("icinga");
                Type::Ptr ptype = Type::GetByName(m_Type);
                ASSERT(ptype);
                return GetFieldCompletionSuggestions(ptype, word);
@@ -175,8 +174,6 @@ int RepositoryObjectCommand::Run(const boost::program_options::variables_map& vm
        }
 
        if (m_Command == RepositoryCommandAdd) {
-               Utility::LoadExtensionLibrary("icinga");
-
                std::vector<String> object_paths = RepositoryUtility::GetObjects();
 
                Array::Ptr changes = new Array();
index 66ae1d281d4a6b26bdee1af127fe019159909a5b..ff3a6f7b3b977150f39792d7358694253ad090c6 100644 (file)
@@ -445,10 +445,6 @@ bool TroubleshootCommand::PrintConf(InfoLog& log, const String& path)
 
 bool TroubleshootCommand::CheckConfig(void)
 {
-       /* Not loading the icinga library would make config validation fail.
-        * (Depending on the configuration and the speed of your machine.)
-        */
-       Utility::LoadExtensionLibrary("icinga");
        std::vector<std::string> configs;
        configs.push_back(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
 
index 10c2a06cd167a0a5aa49b105800a0976276bb98c..5f255f253c92eddb81f0fc65dfd355b1f9204d03 100644 (file)
@@ -21,6 +21,7 @@
 #include "config/configitem.hpp"
 #include "base/logger.hpp"
 #include "base/utility.hpp"
+#include "base/loader.hpp"
 #include "base/context.hpp"
 #include "base/exception.hpp"
 #include <fstream>
@@ -171,7 +172,7 @@ Expression *ConfigCompiler::HandleIncludeRecursive(const String& path, const Str
  */
 void ConfigCompiler::HandleLibrary(const String& library)
 {
-       Utility::LoadExtensionLibrary(library);
+       Loader::LoadExtensionLibrary(library);
 }
 
 void ConfigCompiler::CompileHelper(void)
index 53ce406f15f0fedc3e5aa99bdee21a9e45d5e159..6a9e2b1d7aab6bb16d142c1fee0de7d14cea37d0 100644 (file)
@@ -34,7 +34,7 @@
                        delete expression; \
                } \
                \
-               INITIALIZE_ONCE(RegisterConfigFragment); \
+               INITIALIZE_ONCE_WITH_PRIORITY(RegisterConfigFragment, 5); \
        }
 
 #endif /* CONFIGFRAGMENT_H */
index ce01cc1c1ea6f17227f213572e23bf2b1a13daf8..9c79dff24599f3f3b5d2753f82ed04b1d0d8619e 100644 (file)
@@ -27,6 +27,7 @@
 #include "base/serializer.hpp"
 #include "base/stdiostream.hpp"
 #include "base/json.hpp"
+#include "base/loader.hpp"
 #include "cli/daemonutility.hpp"
 #include <boost/test/unit_test.hpp>
 #include <fstream>
@@ -82,8 +83,8 @@ struct GlobalConfigFixture {
                Application::DeclareSysconfDir("etc");
                Application::DeclareLocalStateDir("var");
 
-               Utility::LoadExtensionLibrary("icinga");
-               Utility::LoadExtensionLibrary("methods"); //loaded by ITL
+               Loader::LoadExtensionLibrary("icinga");
+               Loader::LoadExtensionLibrary("methods"); //loaded by ITL
 
                std::vector<std::string> configs;
                configs.push_back(TestConfig);