]> granicus.if.org Git - icinga2/commitdiff
Dynamically create and destroy the timer thread
authorGunnar Beutner <gunnar.beutner@icinga.com>
Tue, 21 Nov 2017 13:07:44 +0000 (14:07 +0100)
committerGunnar Beutner <gunnar.beutner@icinga.com>
Thu, 30 Nov 2017 16:41:02 +0000 (17:41 +0100)
15 files changed:
lib/base/application.cpp
lib/base/timer.cpp
lib/base/timer.hpp
lib/icinga/comment.cpp
lib/icinga/comment.hpp
lib/icinga/downtime.cpp
lib/icinga/downtime.hpp
lib/icinga/externalcommandprocessor.cpp
lib/icinga/scheduleddowntime.cpp
lib/icinga/scheduleddowntime.hpp
lib/icinga/timeperiod.cpp
lib/icinga/timeperiod.hpp
lib/remote/consolehandler.cpp
lib/remote/jsonrpcconnection-heartbeat.cpp
lib/remote/jsonrpcconnection.cpp

index 23847c03bd850a3034dcf08486c5dc1bbc449706..58ef40b14a016edb793d70b24d8a8aea9850b1df 100644 (file)
@@ -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:
index 2a583b6946ab8911738cfaaa4039f322e96fe48c..79f5ebeef9381a7d310650d4d21f961875afa07c 100644 (file)
@@ -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();
-       }
-
-       if (l_TimerThread.joinable())
-               l_TimerThread.join();
+       {
+              boost::mutex::scoped_lock lock(l_TimerMutex);
+              l_StopTimerThread = true;
+              l_TimerCV.notify_all();
+       }
+
+       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);
 
index d10d1dbe0ce1ec328d7d80694fb7b468957f0e94..37f530dad36e37bfc04b8a43683ecf378b5627a4 100644 (file)
@@ -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;
 };
 
index 497c9a0157f81e9e8f2366bbfa130890fc01a860..84f862e21597ac06b8323b8a2ce2d31295b9fd16 100644 (file)
@@ -26,6 +26,7 @@
 #include "base/timer.hpp"
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
+#include <boost/thread/once.hpp>
 
 using namespace icinga;
 
@@ -37,18 +38,8 @@ static Timer::Ptr l_CommentsExpireTimer;
 boost::signals2::signal<void (const Comment::Ptr&)> Comment::OnCommentAdded;
 boost::signals2::signal<void (const Comment::Ptr&)> 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<Comment>(context);
@@ -106,6 +97,15 @@ void Comment::Start(bool runtimeCreated)
 {
        ObjectImpl<Comment>::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);
 
index 67669ba08a7eada88df8cc8defa06ef7792a32c7..d2ccfa8488a519b423d08db8e02b150e3b540767 100644 (file)
@@ -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;
index 9c9903484042aa8639237bfd02ddc6e484becf4b..bf8b6d214d3eb6aa1cb8056aabf8e1863f0b13c0 100644 (file)
@@ -27,6 +27,7 @@
 #include "base/timer.hpp"
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
+#include <boost/thread/once.hpp>
 
 using namespace icinga;
 
@@ -41,23 +42,8 @@ boost::signals2::signal<void (const Downtime::Ptr&)> Downtime::OnDowntimeRemoved
 boost::signals2::signal<void (const Downtime::Ptr&)> Downtime::OnDowntimeStarted;
 boost::signals2::signal<void (const Downtime::Ptr&)> 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<Downtime>(context);
@@ -115,6 +101,20 @@ void Downtime::Start(bool runtimeCreated)
 {
        ObjectImpl<Downtime>::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);
 
index eb5380b12781ac5a63eb154b37247aa482897448..c5e0ef66e97b8e7015667ddd5605bb5733479e6a 100644 (file)
@@ -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;
index 32db49ec321e8c9289403fbbbc744c6e17c46722..3ea5afe7119754c0180354aff79a53a48afabd0e 100644 (file)
@@ -39,6 +39,7 @@
 #include <fstream>
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
+#include <boost/thread/once.hpp>
 
 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());
 
index be980e68f9468a644d593a8850f3866814063613..305ab77b0e20898b8bfb51d0d6c0b0cb90413191 100644 (file)
@@ -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"
 #include "base/exception.hpp"
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
+#include <boost/thread/once.hpp>
 
 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<ScheduledDowntime>::OnAllConfigLoaded();
@@ -99,6 +89,15 @@ void ScheduledDowntime::Start(bool runtimeCreated)
 {
        ObjectImpl<ScheduledDowntime>::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));
 }
 
index 31f2fd58ad451cccfb68dc92dcf48f287afdf7ef..f171d8e1116a9af63eb87c10e8ff1d3e38d8624f 100644 (file)
@@ -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>& host);
index 004e67538a9b65c2e950d7280ed74a5779cc361a..f0b8b66447f1f6c2d25028ed7f96413a78e34764 100644 (file)
@@ -26,6 +26,7 @@
 #include "base/logger.hpp"
 #include "base/timer.hpp"
 #include "base/utility.hpp"
+#include <boost/thread/once.hpp>
 
 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<TimePeriod>::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);
index 2c0e7a574b5d96668559e76466a0a9253469a46d..23d6ab8db5416508ac3ea4a6e44bb4e927d2c61b 100644 (file)
@@ -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);
index 953bb23b58663a9b37accdd58cb5afa7d3ee0a10..bf69d9559f2d4792a1b15dbeb273e7700c257d73 100644 (file)
@@ -29,6 +29,7 @@
 #include "base/timer.hpp"
 #include "base/initialize.hpp"
 #include <boost/algorithm/string.hpp>
+#include <boost/thread/once.hpp>
 #include <set>
 
 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();
 
index 5485ca8d9f10dee6fe7a4c88372b656fbaddd4d9..d71faa443b99603c42c9bba5653e6e5a5b4d5adb 100644 (file)
@@ -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<Endpoint>()) {
index f3dd038b658e1c26825600b439249103a6364ba9..7309f8f396b962fce4bef8db9ad5ff023c6f44c5 100644 (file)
@@ -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)