Dynamically create and destroy the timer thread

This commit is contained in:
Gunnar Beutner 2017-11-21 14:07:44 +01:00
parent 6d09efc907
commit 6739023678
15 changed files with 101 additions and 97 deletions

View File

@ -158,8 +158,6 @@ void Application::InitializeBase(void)
/* make sure the thread pool gets initialized */ /* make sure the thread pool gets initialized */
GetTP().Start(); GetTP().Start();
Timer::Initialize();
} }
void Application::UninitializeBase(void) void Application::UninitializeBase(void)
@ -317,8 +315,6 @@ void Application::SetArgV(char **argv)
*/ */
void Application::RunEventLoop(void) void Application::RunEventLoop(void)
{ {
Timer::Initialize();
double lastLoop = Utility::GetTime(); double lastLoop = Utility::GetTime();
mainloop: mainloop:

View File

@ -71,6 +71,7 @@ static boost::condition_variable l_TimerCV;
static std::thread l_TimerThread; static std::thread l_TimerThread;
static bool l_StopTimerThread; static bool l_StopTimerThread;
static TimerSet l_Timers; static TimerSet l_Timers;
static int l_AliveTimers;
/** /**
* Constructor for the Timer class. * Constructor for the Timer class.
@ -87,29 +88,16 @@ Timer::~Timer(void)
Stop(true); 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) void Timer::Uninitialize(void)
{ {
{ {
boost::mutex::scoped_lock lock(l_TimerMutex); boost::mutex::scoped_lock lock(l_TimerMutex);
l_StopTimerThread = true; l_StopTimerThread = true;
l_TimerCV.notify_all(); l_TimerCV.notify_all();
} }
if (l_TimerThread.joinable()) if (l_TimerThread.joinable())
l_TimerThread.join(); l_TimerThread.join();
} }
/** /**
@ -158,6 +146,11 @@ void Timer::Start(void)
{ {
boost::mutex::scoped_lock lock(l_TimerMutex); boost::mutex::scoped_lock lock(l_TimerMutex);
m_Started = true; m_Started = true;
if (l_AliveTimers++ == 0) {
l_StopTimerThread = false;
l_TimerThread = std::thread(&Timer::TimerThreadProc);
}
} }
InternalReschedule(false); InternalReschedule(false);
@ -173,6 +166,18 @@ void Timer::Stop(bool wait)
boost::mutex::scoped_lock lock(l_TimerMutex); 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; m_Started = false;
l_Timers.erase(this); l_Timers.erase(this);

View File

@ -41,6 +41,8 @@ public:
Timer(void); Timer(void);
~Timer(void); ~Timer(void);
static void Uninitialize(void);
void SetInterval(double interval); void SetInterval(double interval);
double GetInterval(void) const; double GetInterval(void) const;
@ -65,10 +67,6 @@ private:
static void TimerThreadProc(void); static void TimerThreadProc(void);
static void Initialize(void);
static void Uninitialize(void);
friend class Application;
friend class TimerHolder; friend class TimerHolder;
}; };

View File

@ -26,6 +26,7 @@
#include "base/timer.hpp" #include "base/timer.hpp"
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/thread/once.hpp>
using namespace icinga; 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::OnCommentAdded;
boost::signals2::signal<void (const Comment::Ptr&)> Comment::OnCommentRemoved; boost::signals2::signal<void (const Comment::Ptr&)> Comment::OnCommentRemoved;
INITIALIZE_ONCE(&Comment::StaticInitialize);
REGISTER_TYPE(Comment); 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 String CommentNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
{ {
Comment::Ptr comment = dynamic_pointer_cast<Comment>(context); Comment::Ptr comment = dynamic_pointer_cast<Comment>(context);
@ -106,6 +97,15 @@ void Comment::Start(bool runtimeCreated)
{ {
ObjectImpl<Comment>::Start(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); boost::mutex::scoped_lock lock(l_CommentMutex);

View File

@ -56,8 +56,6 @@ public:
static String GetCommentIDFromLegacyID(int id); static String GetCommentIDFromLegacyID(int id);
static void StaticInitialize(void);
protected: protected:
virtual void OnAllConfigLoaded(void) override; virtual void OnAllConfigLoaded(void) override;
virtual void Start(bool runtimeCreated) override; virtual void Start(bool runtimeCreated) override;

View File

@ -27,6 +27,7 @@
#include "base/timer.hpp" #include "base/timer.hpp"
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/thread/once.hpp>
using namespace icinga; 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::OnDowntimeStarted;
boost::signals2::signal<void (const Downtime::Ptr&)> Downtime::OnDowntimeTriggered; boost::signals2::signal<void (const Downtime::Ptr&)> Downtime::OnDowntimeTriggered;
INITIALIZE_ONCE(&Downtime::StaticInitialize);
REGISTER_TYPE(Downtime); 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 String DowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
{ {
Downtime::Ptr downtime = dynamic_pointer_cast<Downtime>(context); Downtime::Ptr downtime = dynamic_pointer_cast<Downtime>(context);
@ -115,6 +101,20 @@ void Downtime::Start(bool runtimeCreated)
{ {
ObjectImpl<Downtime>::Start(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); boost::mutex::scoped_lock lock(l_DowntimeMutex);

View File

@ -65,8 +65,6 @@ public:
static String GetDowntimeIDFromLegacyID(int id); static String GetDowntimeIDFromLegacyID(int id);
static void StaticInitialize(void);
protected: protected:
virtual void OnAllConfigLoaded(void) override; virtual void OnAllConfigLoaded(void) override;
virtual void Start(bool runtimeCreated) override; virtual void Start(bool runtimeCreated) override;

View File

@ -39,6 +39,7 @@
#include <fstream> #include <fstream>
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/thread/once.hpp>
using namespace icinga; using namespace icinga;
@ -111,6 +112,12 @@ void ExternalCommandProcessor::Execute(double time, const String& command, const
{ {
ExternalCommandInfo eci; ExternalCommandInfo eci;
static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, []() {
RegisterCommands();
});
{ {
boost::mutex::scoped_lock lock(GetMutex()); boost::mutex::scoped_lock lock(GetMutex());

View File

@ -24,7 +24,6 @@
#include "icinga/service.hpp" #include "icinga/service.hpp"
#include "base/timer.hpp" #include "base/timer.hpp"
#include "base/configtype.hpp" #include "base/configtype.hpp"
#include "base/initialize.hpp"
#include "base/utility.hpp" #include "base/utility.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
@ -32,13 +31,12 @@
#include "base/exception.hpp" #include "base/exception.hpp"
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/thread/once.hpp>
using namespace icinga; using namespace icinga;
REGISTER_TYPE(ScheduledDowntime); REGISTER_TYPE(ScheduledDowntime);
INITIALIZE_ONCE(&ScheduledDowntime::StaticInitialize);
static Timer::Ptr l_Timer; static Timer::Ptr l_Timer;
String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const 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; 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) void ScheduledDowntime::OnAllConfigLoaded(void)
{ {
ObjectImpl<ScheduledDowntime>::OnAllConfigLoaded(); ObjectImpl<ScheduledDowntime>::OnAllConfigLoaded();
@ -99,6 +89,15 @@ void ScheduledDowntime::Start(bool runtimeCreated)
{ {
ObjectImpl<ScheduledDowntime>::Start(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)); Utility::QueueAsyncCallback(std::bind(&ScheduledDowntime::CreateNextDowntime, this));
} }

View File

@ -44,8 +44,6 @@ public:
DECLARE_OBJECT(ScheduledDowntime); DECLARE_OBJECT(ScheduledDowntime);
DECLARE_OBJECTNAME(ScheduledDowntime); DECLARE_OBJECTNAME(ScheduledDowntime);
static void StaticInitialize(void);
Checkable::Ptr GetCheckable(void) const; Checkable::Ptr GetCheckable(void) const;
static void EvaluateApplyRules(const intrusive_ptr<Host>& host); static void EvaluateApplyRules(const intrusive_ptr<Host>& host);

View File

@ -26,6 +26,7 @@
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/timer.hpp" #include "base/timer.hpp"
#include "base/utility.hpp" #include "base/utility.hpp"
#include <boost/thread/once.hpp>
using namespace icinga; using namespace icinga;
@ -33,20 +34,19 @@ REGISTER_TYPE(TimePeriod);
static Timer::Ptr l_UpdateTimer; 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) void TimePeriod::Start(bool runtimeCreated)
{ {
ObjectImpl<TimePeriod>::Start(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. */ /* Pre-fill the time period for the next 24 hours. */
double now = Utility::GetTime(); double now = Utility::GetTime();
UpdateRegion(now, now + 24 * 3600, true); UpdateRegion(now, now + 24 * 3600, true);

View File

@ -37,8 +37,6 @@ public:
DECLARE_OBJECT(TimePeriod); DECLARE_OBJECT(TimePeriod);
DECLARE_OBJECTNAME(TimePeriod); DECLARE_OBJECTNAME(TimePeriod);
static void StaticInitialize(void);
virtual void Start(bool runtimeCreated) override; virtual void Start(bool runtimeCreated) override;
void UpdateRegion(double begin, double end, bool clearExisting); void UpdateRegion(double begin, double end, bool clearExisting);

View File

@ -29,6 +29,7 @@
#include "base/timer.hpp" #include "base/timer.hpp"
#include "base/initialize.hpp" #include "base/initialize.hpp"
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/thread/once.hpp>
#include <set> #include <set>
using namespace icinga; using namespace icinga;
@ -57,12 +58,17 @@ static void ScriptFrameCleanupHandler(void)
l_ApiScriptFrames.erase(key); l_ApiScriptFrames.erase(key);
} }
INITIALIZE_ONCE([]() { static void EnsureFrameCleanupTimer(void)
l_FrameCleanupTimer = new Timer(); {
l_FrameCleanupTimer->OnTimerExpired.connect(std::bind(ScriptFrameCleanupHandler)); static boost::once_flag once = BOOST_ONCE_INIT;
l_FrameCleanupTimer->SetInterval(30);
l_FrameCleanupTimer->Start(); 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) 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") Log(LogNotice, "Console")
<< "Executing expression: " << command; << "Executing expression: " << command;
EnsureFrameCleanupTimer();
ApiScriptFrame& lsf = l_ApiScriptFrames[session]; ApiScriptFrame& lsf = l_ApiScriptFrames[session];
lsf.Seen = Utility::GetTime(); lsf.Seen = Utility::GetTime();
@ -175,6 +183,8 @@ bool ConsoleHandler::AutocompleteScriptHelper(HttpRequest& request, HttpResponse
Log(LogInformation, "Console") Log(LogInformation, "Console")
<< "Auto-completing expression: " << command; << "Auto-completing expression: " << command;
EnsureFrameCleanupTimer();
ApiScriptFrame& lsf = l_ApiScriptFrames[session]; ApiScriptFrame& lsf = l_ApiScriptFrames[session];
lsf.Seen = Utility::GetTime(); lsf.Seen = Utility::GetTime();

View File

@ -29,15 +29,6 @@ using namespace icinga;
REGISTER_APIFUNCTION(Heartbeat, event, &JsonRpcConnection::HeartbeatAPIHandler); 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) void JsonRpcConnection::HeartbeatTimerHandler(void)
{ {
for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType<Endpoint>()) { for (const Endpoint::Ptr& endpoint : ConfigType::GetObjectsByType<Endpoint>()) {

View File

@ -39,6 +39,7 @@ static Timer::Ptr l_JsonRpcConnectionTimeoutTimer;
static WorkQueue *l_JsonRpcConnectionWorkQueues; static WorkQueue *l_JsonRpcConnectionWorkQueues;
static size_t l_JsonRpcConnectionWorkQueueCount; static size_t l_JsonRpcConnectionWorkQueueCount;
static int l_JsonRpcConnectionNextID; static int l_JsonRpcConnectionNextID;
static Timer::Ptr l_HeartbeatTimer;
JsonRpcConnection::JsonRpcConnection(const String& identity, bool authenticated, JsonRpcConnection::JsonRpcConnection(const String& identity, bool authenticated,
const TlsStream::Ptr& stream, ConnectionRole role) const TlsStream::Ptr& stream, ConnectionRole role)
@ -65,6 +66,11 @@ void JsonRpcConnection::StaticInitialize(void)
for (size_t i = 0; i < l_JsonRpcConnectionWorkQueueCount; i++) { for (size_t i = 0; i < l_JsonRpcConnectionWorkQueueCount; i++) {
l_JsonRpcConnectionWorkQueues[i].SetName("JsonRpcConnection, #" + Convert::ToString(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) void JsonRpcConnection::Start(void)