From d4afb4087d8bcbb1f4b023bab11d2de45e476291 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 14 Feb 2013 15:39:53 +0100 Subject: [PATCH] Properly shut down instances of the ScriptInterpreter class. --- lib/base/script.cpp | 4 +++ lib/base/scriptinterpreter.cpp | 58 +++++++++++++++++++++++----------- lib/base/scriptinterpreter.h | 8 +++-- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/lib/base/script.cpp b/lib/base/script.cpp index 0bcc5ca77..c324f9828 100644 --- a/lib/base/script.cpp +++ b/lib/base/script.cpp @@ -57,6 +57,10 @@ void Script::SpawnInterpreter(void) { Logger::Write(LogInformation, "base", "Reloading script '" + GetName() + "'"); + if (m_Interpreter) + m_Interpreter->Stop(); + ScriptLanguage::Ptr language = ScriptLanguage::GetByName(GetLanguage()); m_Interpreter = language->CreateInterpreter(GetSelf()); + m_Interpreter->Start(); } diff --git a/lib/base/scriptinterpreter.cpp b/lib/base/scriptinterpreter.cpp index 787ce6883..028edbed1 100644 --- a/lib/base/scriptinterpreter.cpp +++ b/lib/base/scriptinterpreter.cpp @@ -22,19 +22,54 @@ using namespace icinga; ScriptInterpreter::ScriptInterpreter(const Script::Ptr& script) - : m_Thread(&ScriptInterpreter::ThreadWorkerProc, this) +{ } + +ScriptInterpreter::~ScriptInterpreter(void) { - m_Thread.detach(); + Stop(); +} + +void ScriptInterpreter::Start(void) +{ + /* We can't start the thread in the constructor because + * the worker thread might end up calling one of the virtual + * methods before the object is fully constructed. */ + + m_Thread = boost::thread(&ScriptInterpreter::ThreadWorkerProc, this); +} + +void ScriptInterpreter::Stop(void) +{ + { + boost::mutex::scoped_lock lock(m_Mutex); + + if (m_Shutdown) + return; + + m_Shutdown = true; + m_CallAvailable.notify_all(); + } + + m_Thread.join(); } void ScriptInterpreter::ThreadWorkerProc(void) { - ScriptCall call; + boost::mutex::scoped_lock lock(m_Mutex); - while (WaitForCall(&call)) - ProcessCall(call); + for (;;) { + while (m_Calls.empty() && !m_Shutdown) + m_CallAvailable.wait(lock); + + if (m_Shutdown) + break; + + ScriptCall call = m_Calls.front(); + m_Calls.pop_front(); + } } + void ScriptInterpreter::EnqueueCall(const ScriptCall& call) { boost::mutex::scoped_lock lock(m_Mutex); @@ -42,19 +77,6 @@ void ScriptInterpreter::EnqueueCall(const ScriptCall& call) m_CallAvailable.notify_all(); } -bool ScriptInterpreter::WaitForCall(ScriptCall *call) -{ - boost::mutex::scoped_lock lock(m_Mutex); - - while (m_Calls.empty()) - m_CallAvailable.wait(lock); - - *call = m_Calls.front(); - m_Calls.pop_front(); - - return true; -} - void ScriptInterpreter::RegisterMethod(const String& name) { // TODO: implement diff --git a/lib/base/scriptinterpreter.h b/lib/base/scriptinterpreter.h index 1a6dc10ec..a207376dd 100644 --- a/lib/base/scriptinterpreter.h +++ b/lib/base/scriptinterpreter.h @@ -41,19 +41,23 @@ public: typedef shared_ptr Ptr; typedef weak_ptr WeakPtr; + ~ScriptInterpreter(void); + void EnqueueCall(const ScriptCall& call); + void Start(void); + void Stop(void); + protected: ScriptInterpreter(const Script::Ptr& script); virtual void ProcessCall(const ScriptCall& call) = 0; - bool WaitForCall(ScriptCall *call); - void RegisterMethod(const String& name); private: boost::mutex m_Mutex; + bool m_Shutdown; deque m_Calls; condition_variable m_CallAvailable;