diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 0e8c59560..e06fb9555 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -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 >()) { 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()); + Loader::LoadExtensionLibrary(vm["app"].as()); else - Utility::LoadExtensionLibrary("icinga"); + Loader::LoadExtensionLibrary("icinga"); Logger::SetConsoleLogSeverity(logLevel); diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 0a880e2c3..fb7cea75e 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -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 diff --git a/lib/base/application.cpp b/lib/base/application.cpp index dbb5d8dfc..d04f9ac71 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -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(); diff --git a/lib/base/initialize.cpp b/lib/base/initialize.cpp index 5cc4561b9..2042fca88 100644 --- a/lib/base/initialize.cpp +++ b/lib/base/initialize.cpp @@ -18,13 +18,13 @@ ******************************************************************************/ #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; } diff --git a/lib/base/initialize.hpp b/lib/base/initialize.hpp index 62de192da..4b7848af2 100644 --- a/lib/base/initialize.hpp +++ b/lib/base/initialize.hpp @@ -25,13 +25,17 @@ 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 index 000000000..036c16313 --- /dev/null +++ b/lib/base/loader.cpp @@ -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 + +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 >& Loader::GetDeferredInitializers(void) +{ + static boost::thread_specific_ptr > 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& callback, int priority) +{ + if (!GetDeferredInitializers().get()) + GetDeferredInitializers().reset(new std::priority_queue()); + + GetDeferredInitializers().get()->push(DeferredInitializer(callback, priority)); +} + diff --git a/lib/base/loader.hpp b/lib/base/loader.hpp new file mode 100644 index 000000000..aef033c97 --- /dev/null +++ b/lib/base/loader.hpp @@ -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 +#include +#include + +namespace icinga +{ + +struct DeferredInitializer +{ +public: + DeferredInitializer(const boost::function& 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 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& callback, int priority = 0); + static void ExecuteDeferredInitializers(void); + +private: + Loader(void); + + static boost::thread_specific_ptr >& GetDeferredInitializers(void); + +}; + +} + +#endif /* LOADER_H */ diff --git a/lib/base/type.hpp b/lib/base/type.hpp index d1b2adb27..1c123fb1b 100644 --- a/lib/base/type.hpp +++ b/lib/base/type.hpp @@ -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) diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 5fdf25468..dd240a64d 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -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 > >& Utility::GetDeferredInitializers(void) -{ - static boost::thread_specific_ptr > > initializers; - return initializers; -} - -void Utility::ExecuteDeferredInitializers(void) -{ - if (!GetDeferredInitializers().get()) - return; - - BOOST_FOREACH(const boost::function& callback, *GetDeferredInitializers().get()) { - VERIFY(callback); - callback(); - } - - GetDeferredInitializers().reset(); -} - -void Utility::AddDeferredInitializer(const boost::function& callback) -{ - if (!GetDeferredInitializers().get()) - GetDeferredInitializers().reset(new std::vector >()); - - GetDeferredInitializers().get()->push_back(callback); -} - /** * Generates a new unique ID. * diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index c1702193e..7c0e7db18 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -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& 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 m_ThreadName; static boost::thread_specific_ptr m_RandSeed; - static boost::thread_specific_ptr > >& GetDeferredInitializers(void); - }; } diff --git a/lib/cli/nodeupdateconfigcommand.cpp b/lib/cli/nodeupdateconfigcommand.cpp index 905f57858..71a7b889a 100644 --- a/lib/cli/nodeupdateconfigcommand.cpp +++ b/lib/cli/nodeupdateconfigcommand.cpp @@ -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 object_paths = RepositoryUtility::GetObjects(); /* cache all existing changes only once and pass it to AddObject() */ diff --git a/lib/cli/repositoryobjectcommand.cpp b/lib/cli/repositoryobjectcommand.cpp index e50b45faa..4e480f145 100644 --- a/lib/cli/repositoryobjectcommand.cpp +++ b/lib/cli/repositoryobjectcommand.cpp @@ -108,7 +108,6 @@ void RepositoryObjectCommand::InitParameters(boost::program_options::options_des std::vector 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 object_paths = RepositoryUtility::GetObjects(); Array::Ptr changes = new Array(); diff --git a/lib/cli/troubleshootcommand.cpp b/lib/cli/troubleshootcommand.cpp index 66ae1d281..ff3a6f7b3 100644 --- a/lib/cli/troubleshootcommand.cpp +++ b/lib/cli/troubleshootcommand.cpp @@ -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 configs; configs.push_back(Application::GetSysconfDir() + "/icinga2/icinga2.conf"); diff --git a/lib/config/configcompiler.cpp b/lib/config/configcompiler.cpp index 10c2a06cd..5f255f253 100644 --- a/lib/config/configcompiler.cpp +++ b/lib/config/configcompiler.cpp @@ -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 @@ -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) diff --git a/lib/config/configfragment.hpp b/lib/config/configfragment.hpp index 53ce406f1..6a9e2b1d7 100644 --- a/lib/config/configfragment.hpp +++ b/lib/config/configfragment.hpp @@ -34,7 +34,7 @@ delete expression; \ } \ \ - INITIALIZE_ONCE(RegisterConfigFragment); \ + INITIALIZE_ONCE_WITH_PRIORITY(RegisterConfigFragment, 5); \ } #endif /* CONFIGFRAGMENT_H */ diff --git a/test/livestatus.cpp b/test/livestatus.cpp index ce01cc1c1..9c79dff24 100644 --- a/test/livestatus.cpp +++ b/test/livestatus.cpp @@ -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 #include @@ -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 configs; configs.push_back(TestConfig);