diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 23847c03b..58ef40b14 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -158,8 +158,6 @@ void Application::InitializeBase(void) /* make sure the thread pool gets initialized */ GetTP().Start(); - - Timer::Initialize(); } void Application::UninitializeBase(void) @@ -317,8 +315,6 @@ void Application::SetArgV(char **argv) */ void Application::RunEventLoop(void) { - Timer::Initialize(); - double lastLoop = Utility::GetTime(); mainloop: diff --git a/lib/base/timer.cpp b/lib/base/timer.cpp index 2a583b694..79f5ebeef 100644 --- a/lib/base/timer.cpp +++ b/lib/base/timer.cpp @@ -71,6 +71,7 @@ static boost::condition_variable l_TimerCV; static std::thread l_TimerThread; static bool l_StopTimerThread; static TimerSet l_Timers; +static int l_AliveTimers; /** * Constructor for the Timer class. @@ -87,29 +88,16 @@ Timer::~Timer(void) Stop(true); } -/** - * Initializes the timer sub-system. - */ -void Timer::Initialize(void) -{ - boost::mutex::scoped_lock lock(l_TimerMutex); - l_StopTimerThread = false; - l_TimerThread = std::thread(&Timer::TimerThreadProc); -} - -/** - * Disables the timer sub-system. - */ void Timer::Uninitialize(void) { - { - boost::mutex::scoped_lock lock(l_TimerMutex); - l_StopTimerThread = true; - l_TimerCV.notify_all(); - } + { + boost::mutex::scoped_lock lock(l_TimerMutex); + l_StopTimerThread = true; + l_TimerCV.notify_all(); + } - if (l_TimerThread.joinable()) - l_TimerThread.join(); + if (l_TimerThread.joinable()) + l_TimerThread.join(); } /** @@ -158,6 +146,11 @@ void Timer::Start(void) { boost::mutex::scoped_lock lock(l_TimerMutex); m_Started = true; + + if (l_AliveTimers++ == 0) { + l_StopTimerThread = false; + l_TimerThread = std::thread(&Timer::TimerThreadProc); + } } InternalReschedule(false); @@ -173,6 +166,18 @@ void Timer::Stop(bool wait) boost::mutex::scoped_lock lock(l_TimerMutex); + if (m_Started && --l_AliveTimers == 0) { + l_StopTimerThread = true; + l_TimerCV.notify_all(); + + lock.unlock(); + + if (l_TimerThread.joinable() && l_TimerThread.get_id() != std::this_thread::get_id()) + l_TimerThread.join(); + + lock.lock(); + } + m_Started = false; l_Timers.erase(this); diff --git a/lib/base/timer.hpp b/lib/base/timer.hpp index d10d1dbe0..37f530dad 100644 --- a/lib/base/timer.hpp +++ b/lib/base/timer.hpp @@ -41,6 +41,8 @@ public: Timer(void); ~Timer(void); + static void Uninitialize(void); + void SetInterval(double interval); double GetInterval(void) const; @@ -65,10 +67,6 @@ private: static void TimerThreadProc(void); - static void Initialize(void); - static void Uninitialize(void); - - friend class Application; friend class TimerHolder; }; diff --git a/lib/icinga/comment.cpp b/lib/icinga/comment.cpp index 497c9a015..84f862e21 100644 --- a/lib/icinga/comment.cpp +++ b/lib/icinga/comment.cpp @@ -26,6 +26,7 @@ #include "base/timer.hpp" #include #include +#include using namespace icinga; @@ -37,18 +38,8 @@ static Timer::Ptr l_CommentsExpireTimer; boost::signals2::signal Comment::OnCommentAdded; boost::signals2::signal Comment::OnCommentRemoved; -INITIALIZE_ONCE(&Comment::StaticInitialize); - REGISTER_TYPE(Comment); -void Comment::StaticInitialize(void) -{ - l_CommentsExpireTimer = new Timer(); - l_CommentsExpireTimer->SetInterval(60); - l_CommentsExpireTimer->OnTimerExpired.connect(std::bind(&Comment::CommentsExpireTimerHandler)); - l_CommentsExpireTimer->Start(); -} - String CommentNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Comment::Ptr comment = dynamic_pointer_cast(context); @@ -106,6 +97,15 @@ void Comment::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); + static boost::once_flag once = BOOST_ONCE_INIT; + + boost::call_once(once, []() { + l_CommentsExpireTimer = new Timer(); + l_CommentsExpireTimer->SetInterval(60); + l_CommentsExpireTimer->OnTimerExpired.connect(std::bind(&Comment::CommentsExpireTimerHandler)); + l_CommentsExpireTimer->Start(); + }); + { boost::mutex::scoped_lock lock(l_CommentMutex); diff --git a/lib/icinga/comment.hpp b/lib/icinga/comment.hpp index 67669ba08..d2ccfa848 100644 --- a/lib/icinga/comment.hpp +++ b/lib/icinga/comment.hpp @@ -56,8 +56,6 @@ public: static String GetCommentIDFromLegacyID(int id); - static void StaticInitialize(void); - protected: virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; diff --git a/lib/icinga/downtime.cpp b/lib/icinga/downtime.cpp index 9c9903484..bf8b6d214 100644 --- a/lib/icinga/downtime.cpp +++ b/lib/icinga/downtime.cpp @@ -27,6 +27,7 @@ #include "base/timer.hpp" #include #include +#include using namespace icinga; @@ -41,23 +42,8 @@ boost::signals2::signal Downtime::OnDowntimeRemoved boost::signals2::signal Downtime::OnDowntimeStarted; boost::signals2::signal Downtime::OnDowntimeTriggered; -INITIALIZE_ONCE(&Downtime::StaticInitialize); - REGISTER_TYPE(Downtime); -void Downtime::StaticInitialize(void) -{ - l_DowntimesStartTimer = new Timer(); - l_DowntimesStartTimer->SetInterval(5); - l_DowntimesStartTimer->OnTimerExpired.connect(std::bind(&Downtime::DowntimesStartTimerHandler)); - l_DowntimesStartTimer->Start(); - - l_DowntimesExpireTimer = new Timer(); - l_DowntimesExpireTimer->SetInterval(60); - l_DowntimesExpireTimer->OnTimerExpired.connect(std::bind(&Downtime::DowntimesExpireTimerHandler)); - l_DowntimesExpireTimer->Start(); -} - String DowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Downtime::Ptr downtime = dynamic_pointer_cast(context); @@ -115,6 +101,20 @@ void Downtime::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); + static boost::once_flag once = BOOST_ONCE_INIT; + + boost::call_once(once, []() { + l_DowntimesStartTimer = new Timer(); + l_DowntimesStartTimer->SetInterval(5); + l_DowntimesStartTimer->OnTimerExpired.connect(std::bind(&Downtime::DowntimesStartTimerHandler)); + l_DowntimesStartTimer->Start(); + + l_DowntimesExpireTimer = new Timer(); + l_DowntimesExpireTimer->SetInterval(60); + l_DowntimesExpireTimer->OnTimerExpired.connect(std::bind(&Downtime::DowntimesExpireTimerHandler)); + l_DowntimesExpireTimer->Start(); + }); + { boost::mutex::scoped_lock lock(l_DowntimeMutex); diff --git a/lib/icinga/downtime.hpp b/lib/icinga/downtime.hpp index eb5380b12..c5e0ef66e 100644 --- a/lib/icinga/downtime.hpp +++ b/lib/icinga/downtime.hpp @@ -65,8 +65,6 @@ public: static String GetDowntimeIDFromLegacyID(int id); - static void StaticInitialize(void); - protected: virtual void OnAllConfigLoaded(void) override; virtual void Start(bool runtimeCreated) override; diff --git a/lib/icinga/externalcommandprocessor.cpp b/lib/icinga/externalcommandprocessor.cpp index 32db49ec3..3ea5afe71 100644 --- a/lib/icinga/externalcommandprocessor.cpp +++ b/lib/icinga/externalcommandprocessor.cpp @@ -39,6 +39,7 @@ #include #include #include +#include using namespace icinga; @@ -111,6 +112,12 @@ void ExternalCommandProcessor::Execute(double time, const String& command, const { ExternalCommandInfo eci; + static boost::once_flag once = BOOST_ONCE_INIT; + + boost::call_once(once, []() { + RegisterCommands(); + }); + { boost::mutex::scoped_lock lock(GetMutex()); diff --git a/lib/icinga/scheduleddowntime.cpp b/lib/icinga/scheduleddowntime.cpp index be980e68f..305ab77b0 100644 --- a/lib/icinga/scheduleddowntime.cpp +++ b/lib/icinga/scheduleddowntime.cpp @@ -24,7 +24,6 @@ #include "icinga/service.hpp" #include "base/timer.hpp" #include "base/configtype.hpp" -#include "base/initialize.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" @@ -32,13 +31,12 @@ #include "base/exception.hpp" #include #include +#include using namespace icinga; REGISTER_TYPE(ScheduledDowntime); -INITIALIZE_ONCE(&ScheduledDowntime::StaticInitialize); - static Timer::Ptr l_Timer; String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const @@ -79,14 +77,6 @@ Dictionary::Ptr ScheduledDowntimeNameComposer::ParseName(const String& name) con return result; } -void ScheduledDowntime::StaticInitialize(void) -{ - l_Timer = new Timer(); - l_Timer->SetInterval(60); - l_Timer->OnTimerExpired.connect(std::bind(&ScheduledDowntime::TimerProc)); - l_Timer->Start(); -} - void ScheduledDowntime::OnAllConfigLoaded(void) { ObjectImpl::OnAllConfigLoaded(); @@ -99,6 +89,15 @@ void ScheduledDowntime::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); + static boost::once_flag once = BOOST_ONCE_INIT; + + boost::call_once(once, []() { + l_Timer = new Timer(); + l_Timer->SetInterval(60); + l_Timer->OnTimerExpired.connect(std::bind(&ScheduledDowntime::TimerProc)); + l_Timer->Start(); + }); + Utility::QueueAsyncCallback(std::bind(&ScheduledDowntime::CreateNextDowntime, this)); } diff --git a/lib/icinga/scheduleddowntime.hpp b/lib/icinga/scheduleddowntime.hpp index 31f2fd58a..f171d8e11 100644 --- a/lib/icinga/scheduleddowntime.hpp +++ b/lib/icinga/scheduleddowntime.hpp @@ -44,8 +44,6 @@ public: DECLARE_OBJECT(ScheduledDowntime); DECLARE_OBJECTNAME(ScheduledDowntime); - static void StaticInitialize(void); - Checkable::Ptr GetCheckable(void) const; static void EvaluateApplyRules(const intrusive_ptr& host); diff --git a/lib/icinga/timeperiod.cpp b/lib/icinga/timeperiod.cpp index 004e67538..f0b8b6644 100644 --- a/lib/icinga/timeperiod.cpp +++ b/lib/icinga/timeperiod.cpp @@ -26,6 +26,7 @@ #include "base/logger.hpp" #include "base/timer.hpp" #include "base/utility.hpp" +#include using namespace icinga; @@ -33,20 +34,19 @@ REGISTER_TYPE(TimePeriod); static Timer::Ptr l_UpdateTimer; -INITIALIZE_ONCE(&TimePeriod::StaticInitialize); - -void TimePeriod::StaticInitialize(void) -{ - l_UpdateTimer = new Timer(); - l_UpdateTimer->SetInterval(300); - l_UpdateTimer->OnTimerExpired.connect(std::bind(&TimePeriod::UpdateTimerHandler)); - l_UpdateTimer->Start(); -} - void TimePeriod::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); + static boost::once_flag once = BOOST_ONCE_INIT; + + boost::call_once(once, []() { + l_UpdateTimer = new Timer(); + l_UpdateTimer->SetInterval(300); + l_UpdateTimer->OnTimerExpired.connect(std::bind(&TimePeriod::UpdateTimerHandler)); + l_UpdateTimer->Start(); + }); + /* Pre-fill the time period for the next 24 hours. */ double now = Utility::GetTime(); UpdateRegion(now, now + 24 * 3600, true); diff --git a/lib/icinga/timeperiod.hpp b/lib/icinga/timeperiod.hpp index 2c0e7a574..23d6ab8db 100644 --- a/lib/icinga/timeperiod.hpp +++ b/lib/icinga/timeperiod.hpp @@ -37,8 +37,6 @@ public: DECLARE_OBJECT(TimePeriod); DECLARE_OBJECTNAME(TimePeriod); - static void StaticInitialize(void); - virtual void Start(bool runtimeCreated) override; void UpdateRegion(double begin, double end, bool clearExisting); diff --git a/lib/remote/consolehandler.cpp b/lib/remote/consolehandler.cpp index 953bb23b5..bf69d9559 100644 --- a/lib/remote/consolehandler.cpp +++ b/lib/remote/consolehandler.cpp @@ -29,6 +29,7 @@ #include "base/timer.hpp" #include "base/initialize.hpp" #include +#include #include using namespace icinga; @@ -57,12 +58,17 @@ static void ScriptFrameCleanupHandler(void) l_ApiScriptFrames.erase(key); } -INITIALIZE_ONCE([]() { - l_FrameCleanupTimer = new Timer(); - l_FrameCleanupTimer->OnTimerExpired.connect(std::bind(ScriptFrameCleanupHandler)); - l_FrameCleanupTimer->SetInterval(30); - l_FrameCleanupTimer->Start(); -}); +static void EnsureFrameCleanupTimer(void) +{ + static boost::once_flag once = BOOST_ONCE_INIT; + + boost::call_once(once, []() { + l_FrameCleanupTimer = new Timer(); + l_FrameCleanupTimer->OnTimerExpired.connect(std::bind(ScriptFrameCleanupHandler)); + l_FrameCleanupTimer->SetInterval(30); + l_FrameCleanupTimer->Start(); + }); +} bool ConsoleHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { @@ -102,6 +108,8 @@ bool ConsoleHandler::ExecuteScriptHelper(HttpRequest& request, HttpResponse& res Log(LogNotice, "Console") << "Executing expression: " << command; + EnsureFrameCleanupTimer(); + ApiScriptFrame& lsf = l_ApiScriptFrames[session]; lsf.Seen = Utility::GetTime(); @@ -175,6 +183,8 @@ bool ConsoleHandler::AutocompleteScriptHelper(HttpRequest& request, HttpResponse Log(LogInformation, "Console") << "Auto-completing expression: " << command; + EnsureFrameCleanupTimer(); + ApiScriptFrame& lsf = l_ApiScriptFrames[session]; lsf.Seen = Utility::GetTime(); diff --git a/lib/remote/jsonrpcconnection-heartbeat.cpp b/lib/remote/jsonrpcconnection-heartbeat.cpp index 5485ca8d9..d71faa443 100644 --- a/lib/remote/jsonrpcconnection-heartbeat.cpp +++ b/lib/remote/jsonrpcconnection-heartbeat.cpp @@ -29,15 +29,6 @@ using namespace icinga; REGISTER_APIFUNCTION(Heartbeat, event, &JsonRpcConnection::HeartbeatAPIHandler); -static Timer::Ptr l_HeartbeatTimer; - -INITIALIZE_ONCE([]() { - l_HeartbeatTimer = new Timer(); - l_HeartbeatTimer->OnTimerExpired.connect(std::bind(&JsonRpcConnection::HeartbeatTimerHandler)); - l_HeartbeatTimer->SetInterval(10); - l_HeartbeatTimer->Start(); -}); - void JsonRpcConnection::HeartbeatTimerHandler(void) { for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType()) { diff --git a/lib/remote/jsonrpcconnection.cpp b/lib/remote/jsonrpcconnection.cpp index f3dd038b6..7309f8f39 100644 --- a/lib/remote/jsonrpcconnection.cpp +++ b/lib/remote/jsonrpcconnection.cpp @@ -39,6 +39,7 @@ static Timer::Ptr l_JsonRpcConnectionTimeoutTimer; static WorkQueue *l_JsonRpcConnectionWorkQueues; static size_t l_JsonRpcConnectionWorkQueueCount; static int l_JsonRpcConnectionNextID; +static Timer::Ptr l_HeartbeatTimer; JsonRpcConnection::JsonRpcConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream, ConnectionRole role) @@ -65,6 +66,11 @@ void JsonRpcConnection::StaticInitialize(void) for (size_t i = 0; i < l_JsonRpcConnectionWorkQueueCount; i++) { l_JsonRpcConnectionWorkQueues[i].SetName("JsonRpcConnection, #" + Convert::ToString(i)); } + + l_HeartbeatTimer = new Timer(); + l_HeartbeatTimer->OnTimerExpired.connect(std::bind(&JsonRpcConnection::HeartbeatTimerHandler)); + l_HeartbeatTimer->SetInterval(10); + l_HeartbeatTimer->Start(); } void JsonRpcConnection::Start(void)