Merge pull request #9606 from Icinga/initialize-once

INITIALIZE_ONCE_WITH_PRIORITY: use enum for priority values and use std::function
This commit is contained in:
Alexander Aleksandrovič Klimov 2023-01-18 21:10:58 +01:00 committed by GitHub
commit a0286e9c64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 52 additions and 27 deletions

View File

@ -61,28 +61,28 @@ private:
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
nsp->SetAttribute(#name, new ConstEmbeddedNamespaceValue(sf)); \ nsp->SetAttribute(#name, new ConstEmbeddedNamespaceValue(sf)); \
}, 10) }, InitializePriority::RegisterFunctions)
#define REGISTER_SAFE_FUNCTION(ns, name, callback, args) \ #define REGISTER_SAFE_FUNCTION(ns, name, callback, args) \
INITIALIZE_ONCE_WITH_PRIORITY([]() { \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
nsp->SetAttribute(#name, new ConstEmbeddedNamespaceValue(sf)); \ nsp->SetAttribute(#name, new ConstEmbeddedNamespaceValue(sf)); \
}, 10) }, InitializePriority::RegisterFunctions)
#define REGISTER_FUNCTION_NONCONST(ns, name, callback, args) \ #define REGISTER_FUNCTION_NONCONST(ns, name, callback, args) \
INITIALIZE_ONCE_WITH_PRIORITY([]() { \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
nsp->SetAttribute(#name, new EmbeddedNamespaceValue(sf)); \ nsp->SetAttribute(#name, new EmbeddedNamespaceValue(sf)); \
}, 10) }, InitializePriority::RegisterFunctions)
#define REGISTER_SAFE_FUNCTION_NONCONST(ns, name, callback, args) \ #define REGISTER_SAFE_FUNCTION_NONCONST(ns, name, callback, args) \
INITIALIZE_ONCE_WITH_PRIORITY([]() { \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
nsp->SetAttribute(#name, new EmbeddedNamespaceValue(sf)); \ nsp->SetAttribute(#name, new EmbeddedNamespaceValue(sf)); \
}, 10) }, InitializePriority::RegisterFunctions)
} }

View File

@ -5,7 +5,7 @@
using namespace icinga; using namespace icinga;
bool icinga::InitializeOnceHelper(void (*func)(), int priority) bool icinga::InitializeOnceHelper(const std::function<void()>& func, InitializePriority priority)
{ {
Loader::AddDeferredInitializer(func, priority); Loader::AddDeferredInitializer(func, priority);
return true; return true;

View File

@ -4,16 +4,35 @@
#define INITIALIZE_H #define INITIALIZE_H
#include "base/i2-base.hpp" #include "base/i2-base.hpp"
#include <functional>
namespace icinga namespace icinga
{ {
/**
* Priority values for use with the INITIALIZE_ONCE_WITH_PRIORITY macro.
*
* The values are given in the order of initialization.
*/
enum class InitializePriority {
CreateNamespaces,
InitIcingaApplication,
RegisterTypeType,
RegisterObjectType,
RegisterPrimitiveTypes,
RegisterBuiltinTypes,
RegisterFunctions,
RegisterTypes,
EvaluateConfigFragments,
Default,
};
#define I2_TOKENPASTE(x, y) x ## y #define I2_TOKENPASTE(x, y) x ## y
#define I2_TOKENPASTE2(x, y) I2_TOKENPASTE(x, y) #define I2_TOKENPASTE2(x, y) I2_TOKENPASTE(x, y)
#define I2_UNIQUE_NAME(prefix) I2_TOKENPASTE2(prefix, __COUNTER__) #define I2_UNIQUE_NAME(prefix) I2_TOKENPASTE2(prefix, __COUNTER__)
bool InitializeOnceHelper(void (*func)(), int priority = 0); bool InitializeOnceHelper(const std::function<void()>& func, InitializePriority priority = InitializePriority::Default);
#define INITIALIZE_ONCE(func) \ #define INITIALIZE_ONCE(func) \
namespace { namespace I2_UNIQUE_NAME(io) { \ namespace { namespace I2_UNIQUE_NAME(io) { \

View File

@ -7,9 +7,9 @@
using namespace icinga; using namespace icinga;
boost::thread_specific_ptr<std::priority_queue<DeferredInitializer> >& Loader::GetDeferredInitializers() boost::thread_specific_ptr<Loader::DeferredInitializerPriorityQueue>& Loader::GetDeferredInitializers()
{ {
static boost::thread_specific_ptr<std::priority_queue<DeferredInitializer> > initializers; static boost::thread_specific_ptr<DeferredInitializerPriorityQueue> initializers;
return initializers; return initializers;
} }
@ -25,10 +25,10 @@ void Loader::ExecuteDeferredInitializers()
} }
} }
void Loader::AddDeferredInitializer(const std::function<void()>& callback, int priority) void Loader::AddDeferredInitializer(const std::function<void()>& callback, InitializePriority priority)
{ {
if (!GetDeferredInitializers().get()) if (!GetDeferredInitializers().get())
GetDeferredInitializers().reset(new std::priority_queue<DeferredInitializer>()); GetDeferredInitializers().reset(new Loader::DeferredInitializerPriorityQueue());
GetDeferredInitializers().get()->push(DeferredInitializer(callback, priority)); GetDeferredInitializers().get()->push(DeferredInitializer(callback, priority));
} }

View File

@ -4,6 +4,7 @@
#define LOADER_H #define LOADER_H
#include "base/i2-base.hpp" #include "base/i2-base.hpp"
#include "base/initialize.hpp"
#include "base/string.hpp" #include "base/string.hpp"
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include <queue> #include <queue>
@ -14,13 +15,13 @@ namespace icinga
struct DeferredInitializer struct DeferredInitializer
{ {
public: public:
DeferredInitializer(std::function<void ()> callback, int priority) DeferredInitializer(std::function<void ()> callback, InitializePriority priority)
: m_Callback(std::move(callback)), m_Priority(priority) : m_Callback(std::move(callback)), m_Priority(priority)
{ } { }
bool operator<(const DeferredInitializer& other) const bool operator>(const DeferredInitializer& other) const
{ {
return m_Priority < other.m_Priority; return m_Priority > other.m_Priority;
} }
void operator()() void operator()()
@ -30,7 +31,7 @@ public:
private: private:
std::function<void ()> m_Callback; std::function<void ()> m_Callback;
int m_Priority; InitializePriority m_Priority;
}; };
/** /**
@ -41,13 +42,18 @@ private:
class Loader class Loader
{ {
public: public:
static void AddDeferredInitializer(const std::function<void ()>& callback, int priority = 0); static void AddDeferredInitializer(const std::function<void ()>& callback, InitializePriority priority = InitializePriority::Default);
static void ExecuteDeferredInitializers(); static void ExecuteDeferredInitializers();
private: private:
Loader(); Loader();
static boost::thread_specific_ptr<std::priority_queue<DeferredInitializer> >& GetDeferredInitializers(); // Deferred initializers are run in the order of the definition of their enum values.
// Therefore, initializers that should be run first have lower enum values and
// the order of the std::priority_queue has to be reversed using std::greater.
using DeferredInitializerPriorityQueue = std::priority_queue<DeferredInitializer, std::vector<DeferredInitializer>, std::greater<>>;
static boost::thread_specific_ptr<DeferredInitializerPriorityQueue>& GetDeferredInitializers();
}; };
} }

View File

@ -12,7 +12,7 @@ INITIALIZE_ONCE_WITH_PRIORITY([]() {
type->SetPrototype(Object::GetPrototype()); type->SetPrototype(Object::GetPrototype());
Type::Register(type); Type::Register(type);
Object::TypeInstance = type; Object::TypeInstance = type;
}, 20); }, InitializePriority::RegisterObjectType);
String ObjectType::GetName() const String ObjectType::GetName() const
{ {

View File

@ -37,7 +37,7 @@ private:
icinga::Type::Ptr t = new PrimitiveType(#type, "None"); \ icinga::Type::Ptr t = new PrimitiveType(#type, "None"); \
t->SetPrototype(prototype); \ t->SetPrototype(prototype); \
icinga::Type::Register(t); \ icinga::Type::Register(t); \
}, 15) }, InitializePriority::RegisterBuiltinTypes)
#define REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, factory) \ #define REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, factory) \
INITIALIZE_ONCE_WITH_PRIORITY([]() { \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \
@ -45,7 +45,7 @@ private:
t->SetPrototype(prototype); \ t->SetPrototype(prototype); \
icinga::Type::Register(t); \ icinga::Type::Register(t); \
type::TypeInstance = t; \ type::TypeInstance = t; \
}, 15); \ }, InitializePriority::RegisterPrimitiveTypes); \
DEFINE_TYPE_INSTANCE(type) DEFINE_TYPE_INSTANCE(type)
#define REGISTER_PRIMITIVE_TYPE(type, base, prototype) \ #define REGISTER_PRIMITIVE_TYPE(type, base, prototype) \

View File

@ -35,11 +35,11 @@ INITIALIZE_ONCE_WITH_PRIORITY([]() {
l_InternalNS = new Namespace(true); l_InternalNS = new Namespace(true);
globalNS->SetAttribute("Internal", new ConstEmbeddedNamespaceValue(l_InternalNS)); globalNS->SetAttribute("Internal", new ConstEmbeddedNamespaceValue(l_InternalNS));
}, 1000); }, InitializePriority::CreateNamespaces);
INITIALIZE_ONCE_WITH_PRIORITY([]() { INITIALIZE_ONCE([]() {
l_InternalNS->Freeze(); l_InternalNS->Freeze();
}, 0); });
ScriptFrame::ScriptFrame(bool allocLocals) ScriptFrame::ScriptFrame(bool allocLocals)
: Locals(allocLocals ? new Dictionary() : nullptr), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0) : Locals(allocLocals ? new Dictionary() : nullptr), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0)

View File

@ -15,7 +15,7 @@ INITIALIZE_ONCE_WITH_PRIORITY([]() {
type->SetPrototype(TypeType::GetPrototype()); type->SetPrototype(TypeType::GetPrototype());
Type::TypeInstance = type; Type::TypeInstance = type;
Type::Register(type); Type::Register(type);
}, 20); }, InitializePriority::RegisterTypeType);
String Type::ToString() const String Type::ToString() const
{ {

View File

@ -128,7 +128,7 @@ class TypeImpl
icinga::Type::Ptr t = new TypeImpl<type>(); \ icinga::Type::Ptr t = new TypeImpl<type>(); \
type::TypeInstance = t; \ type::TypeInstance = t; \
icinga::Type::Register(t); \ icinga::Type::Register(t); \
}, 10); \ }, InitializePriority::RegisterTypes); \
DEFINE_TYPE_INSTANCE(type) DEFINE_TYPE_INSTANCE(type)
#define REGISTER_TYPE_WITH_PROTOTYPE(type, prototype) \ #define REGISTER_TYPE_WITH_PROTOTYPE(type, prototype) \
@ -137,7 +137,7 @@ class TypeImpl
t->SetPrototype(prototype); \ t->SetPrototype(prototype); \
type::TypeInstance = t; \ type::TypeInstance = t; \
icinga::Type::Register(t); \ icinga::Type::Register(t); \
}, 10); \ }, InitializePriority::RegisterTypes); \
DEFINE_TYPE_INSTANCE(type) DEFINE_TYPE_INSTANCE(type)
#define DEFINE_TYPE_INSTANCE(type) \ #define DEFINE_TYPE_INSTANCE(type) \

View File

@ -21,6 +21,6 @@
std::cerr << icinga::DiagnosticInformation(ex) << std::endl; \ std::cerr << icinga::DiagnosticInformation(ex) << std::endl; \
icinga::Application::Exit(1); \ icinga::Application::Exit(1); \
} \ } \
}, 5) }, icinga::InitializePriority::EvaluateConfigFragments)
#endif /* CONFIGFRAGMENT_H */ #endif /* CONFIGFRAGMENT_H */

View File

@ -26,7 +26,7 @@ static Timer::Ptr l_RetentionTimer;
REGISTER_TYPE(IcingaApplication); REGISTER_TYPE(IcingaApplication);
/* Ensure that the priority is lower than the basic System namespace initialization in scriptframe.cpp. */ /* Ensure that the priority is lower than the basic System namespace initialization in scriptframe.cpp. */
INITIALIZE_ONCE_WITH_PRIORITY(&IcingaApplication::StaticInitialize, 50); INITIALIZE_ONCE_WITH_PRIORITY(&IcingaApplication::StaticInitialize, InitializePriority::InitIcingaApplication);
void IcingaApplication::StaticInitialize() void IcingaApplication::StaticInitialize()
{ {