mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-28 16:14:09 +02:00
Bugfixes for the AsyncTask class.
This commit is contained in:
parent
310edc1074
commit
18bbde330c
@ -7,7 +7,6 @@ pkglib_LTLIBRARIES = \
|
|||||||
libbase_la_SOURCES = \
|
libbase_la_SOURCES = \
|
||||||
application.cpp \
|
application.cpp \
|
||||||
application.h \
|
application.h \
|
||||||
asynctask.cpp \
|
|
||||||
asynctask.h \
|
asynctask.h \
|
||||||
component.cpp \
|
component.cpp \
|
||||||
component.h \
|
component.h \
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
#include "i2-base.h"
|
|
||||||
|
|
||||||
using namespace icinga;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the AsyncTaskBase class.
|
|
||||||
*/
|
|
||||||
AsyncTaskBase::AsyncTaskBase(void)
|
|
||||||
: m_Finished(false), m_ResultRetrieved(false)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor for the AsyncTaskBase class.
|
|
||||||
*/
|
|
||||||
AsyncTaskBase::~AsyncTaskBase(void)
|
|
||||||
{
|
|
||||||
if (!m_Finished) {
|
|
||||||
Logger::Write(LogCritical, "base", "Contract violation: "
|
|
||||||
"AsyncTask was destroyed before its completion callback was invoked.");
|
|
||||||
} else if (!m_ResultRetrieved) {
|
|
||||||
Logger::Write(LogCritical, "base", "Contract violation: "
|
|
||||||
"AsyncTask was destroyed before its result was retrieved.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the async task. The caller must hold a reference to the AsyncTask
|
|
||||||
* object until the completion callback is invoked.
|
|
||||||
*/
|
|
||||||
void AsyncTaskBase::Start(void)
|
|
||||||
{
|
|
||||||
assert(Application::IsMainThread());
|
|
||||||
|
|
||||||
CallWithExceptionGuard(boost::bind(&AsyncTaskBase::Run, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finishes the task using an exception.
|
|
||||||
*
|
|
||||||
* @param ex The exception.
|
|
||||||
*/
|
|
||||||
void AsyncTaskBase::Finish(const boost::exception_ptr& ex)
|
|
||||||
{
|
|
||||||
m_Exception = ex;
|
|
||||||
|
|
||||||
FinishInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finishes the task and causes the completion callback to be invoked. This
|
|
||||||
* function must be called before the object is destroyed.
|
|
||||||
*/
|
|
||||||
void AsyncTaskBase::FinishInternal(void)
|
|
||||||
{
|
|
||||||
assert(!m_Finished);
|
|
||||||
|
|
||||||
Event::Post(boost::bind(&AsyncTaskBase::InvokeCompletionCallback,
|
|
||||||
static_cast<AsyncTaskBase::Ptr>(GetSelf())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes the provided callback function and catches any exceptions it throws.
|
|
||||||
* Exceptions are stored into the task so that they can be re-thrown when the
|
|
||||||
* task owner calls GetResult().
|
|
||||||
*
|
|
||||||
* @param task The task where exceptions should be saved.
|
|
||||||
* @param function The function that should be invoked.
|
|
||||||
* @returns true if no exception occured, false otherwise.
|
|
||||||
*/
|
|
||||||
bool AsyncTaskBase::CallWithExceptionGuard(function<void ()> function)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
function();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (const exception&) {
|
|
||||||
Finish(boost::current_exception());
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
126
base/asynctask.h
126
base/asynctask.h
@ -23,39 +23,13 @@
|
|||||||
namespace icinga
|
namespace icinga
|
||||||
{
|
{
|
||||||
|
|
||||||
class I2_BASE_API AsyncTaskBase : public Object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef shared_ptr<AsyncTaskBase> Ptr;
|
|
||||||
typedef weak_ptr<AsyncTaskBase> WeakPtr;
|
|
||||||
|
|
||||||
AsyncTaskBase(void);
|
|
||||||
~AsyncTaskBase(void);
|
|
||||||
|
|
||||||
void Start(void);
|
|
||||||
void Finish(const boost::exception_ptr& ex);
|
|
||||||
|
|
||||||
bool CallWithExceptionGuard(function<void ()> function);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void Run(void) = 0;
|
|
||||||
|
|
||||||
virtual void InvokeCompletionCallback(void) = 0;
|
|
||||||
|
|
||||||
void FinishInternal(void);
|
|
||||||
|
|
||||||
bool m_Finished; /**< Whether the task is finished. */
|
|
||||||
bool m_ResultRetrieved; /**< Whether the result was retrieved. */
|
|
||||||
boost::exception_ptr m_Exception;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An asynchronous task.
|
* An asynchronous task.
|
||||||
*
|
*
|
||||||
* @ingroup base
|
* @ingroup base
|
||||||
*/
|
*/
|
||||||
template<typename TClass, typename TResult>
|
template<typename TClass, typename TResult>
|
||||||
class AsyncTask : public AsyncTaskBase
|
class AsyncTask : public Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef shared_ptr<AsyncTask<TClass, TResult> > Ptr;
|
typedef shared_ptr<AsyncTask<TClass, TResult> > Ptr;
|
||||||
@ -65,13 +39,39 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the AsyncTask class.
|
* Constructor for the AsyncTask class.
|
||||||
*
|
|
||||||
* @param completionCallback Function that is called when the task is completed.
|
|
||||||
*/
|
*/
|
||||||
AsyncTask(const CompletionCallback& completionCallback)
|
AsyncTask(void)
|
||||||
: m_CompletionCallback(completionCallback)
|
: m_Finished(false), m_ResultRetrieved(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor for the AsyncTask class.
|
||||||
|
*/
|
||||||
|
~AsyncTask(void)
|
||||||
|
{
|
||||||
|
if (!m_Finished) {
|
||||||
|
Logger::Write(LogCritical, "base", "Contract violation: "
|
||||||
|
"AsyncTask was destroyed before its completion callback was invoked.");
|
||||||
|
} else if (!m_ResultRetrieved) {
|
||||||
|
Logger::Write(LogCritical, "base", "Contract violation: "
|
||||||
|
"AsyncTask was destroyed before its result was retrieved.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the async task. The caller must hold a reference to the AsyncTask
|
||||||
|
* object until the completion callback is invoked.
|
||||||
|
*/
|
||||||
|
void Start(const CompletionCallback& completionCallback)
|
||||||
|
{
|
||||||
|
assert(Application::IsMainThread());
|
||||||
|
|
||||||
|
m_CompletionCallback = completionCallback;
|
||||||
|
|
||||||
|
CallWithExceptionGuard(boost::bind(&AsyncTask<TClass, TResult>::Run, this));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the result of the task. Throws an exception if one is stored in
|
* Retrieves the result of the task. Throws an exception if one is stored in
|
||||||
* the AsyncTask object.
|
* the AsyncTask object.
|
||||||
@ -89,21 +89,66 @@ public:
|
|||||||
if (m_Exception)
|
if (m_Exception)
|
||||||
boost::rethrow_exception(m_Exception);
|
boost::rethrow_exception(m_Exception);
|
||||||
|
|
||||||
return m_Result;
|
m_ResultRetrieved = true;
|
||||||
|
|
||||||
|
TResult result;
|
||||||
|
std::swap(m_Result, result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes the task using an exception.
|
||||||
|
*
|
||||||
|
* @param ex The exception.
|
||||||
|
*/
|
||||||
|
void Finish(const boost::exception_ptr& ex)
|
||||||
|
{
|
||||||
|
m_Exception = ex;
|
||||||
|
FinishInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes the task using an ordinary result.
|
||||||
|
*
|
||||||
|
* @param result The result.
|
||||||
|
*/
|
||||||
void Finish(const TResult& result)
|
void Finish(const TResult& result)
|
||||||
{
|
{
|
||||||
m_Result = result;
|
m_Result = result;
|
||||||
FinishInternal();
|
FinishInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the provided callback function and catches any exceptions it throws.
|
||||||
|
* Exceptions are stored into the task so that they can be re-thrown when the
|
||||||
|
* task owner calls GetResult().
|
||||||
|
*
|
||||||
|
* @param task The task where exceptions should be saved.
|
||||||
|
* @param function The function that should be invoked.
|
||||||
|
* @returns true if no exception occured, false otherwise.
|
||||||
|
*/
|
||||||
|
bool CallWithExceptionGuard(function<void ()> function)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
function();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (const exception&) {
|
||||||
|
Finish(boost::current_exception());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void Run(void) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Used by the Finish method to proxy the completion callback into the main
|
* Used by the Finish method to proxy the completion callback into the main
|
||||||
* thread. Invokes the completion callback and marks the task as finished.
|
* thread. Invokes the completion callback and marks the task as finished.
|
||||||
*/
|
*/
|
||||||
virtual void InvokeCompletionCallback(void)
|
void InvokeCompletionCallback(void)
|
||||||
{
|
{
|
||||||
m_Finished = true;
|
m_Finished = true;
|
||||||
m_CompletionCallback(GetSelf());
|
m_CompletionCallback(GetSelf());
|
||||||
@ -113,8 +158,23 @@ private:
|
|||||||
m_CompletionCallback = CompletionCallback();
|
m_CompletionCallback = CompletionCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes the task and causes the completion callback to be invoked. This
|
||||||
|
* function must be called before the object is destroyed.
|
||||||
|
*/
|
||||||
|
void FinishInternal(void)
|
||||||
|
{
|
||||||
|
assert(!m_Finished);
|
||||||
|
|
||||||
|
Event::Post(boost::bind(&AsyncTask<TClass, TResult>::InvokeCompletionCallback, this));
|
||||||
|
}
|
||||||
|
|
||||||
CompletionCallback m_CompletionCallback; /**< The completion callback. */
|
CompletionCallback m_CompletionCallback; /**< The completion callback. */
|
||||||
TResult m_Result; /**< The task's result. */
|
TResult m_Result; /**< The task's result. */
|
||||||
|
boost::exception_ptr m_Exception; /**< The task's exception. */
|
||||||
|
|
||||||
|
bool m_Finished; /**< Whether the task is finished. */
|
||||||
|
bool m_ResultRetrieved; /**< Whether the result was retrieved. */
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="application.cpp" />
|
<ClCompile Include="application.cpp" />
|
||||||
<ClCompile Include="asynctask.cpp" />
|
|
||||||
<ClCompile Include="component.cpp" />
|
<ClCompile Include="component.cpp" />
|
||||||
<ClCompile Include="configobject.cpp" />
|
<ClCompile Include="configobject.cpp" />
|
||||||
<ClCompile Include="dictionary.cpp" />
|
<ClCompile Include="dictionary.cpp" />
|
||||||
|
@ -85,9 +85,6 @@
|
|||||||
<ClCompile Include="scripttask.cpp">
|
<ClCompile Include="scripttask.cpp">
|
||||||
<Filter>Quelldateien</Filter>
|
<Filter>Quelldateien</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="asynctask.cpp">
|
|
||||||
<Filter>Quelldateien</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="i2-base.cpp">
|
<ClCompile Include="i2-base.cpp">
|
||||||
<Filter>Quelldateien</Filter>
|
<Filter>Quelldateien</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -210,8 +210,8 @@ ScriptTask::Ptr ConfigObject::InvokeHook(const string& hook,
|
|||||||
if (!func)
|
if (!func)
|
||||||
throw invalid_argument("Function '" + funcName + "' does not exist.");
|
throw invalid_argument("Function '" + funcName + "' does not exist.");
|
||||||
|
|
||||||
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments, callback);
|
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments);
|
||||||
task->Start();
|
task->Start(callback);
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,7 @@ using boost::system_time;
|
|||||||
#include "tcpclient.h"
|
#include "tcpclient.h"
|
||||||
#include "tcpserver.h"
|
#include "tcpserver.h"
|
||||||
#include "tlsclient.h"
|
#include "tlsclient.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "asynctask.h"
|
#include "asynctask.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "scriptfunction.h"
|
#include "scriptfunction.h"
|
||||||
@ -177,7 +178,6 @@ using boost::system_time;
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
#include "threadpool.h"
|
#include "threadpool.h"
|
||||||
#include "logger.h"
|
|
||||||
#include "streamlogger.h"
|
#include "streamlogger.h"
|
||||||
#include "sysloglogger.h"
|
#include "sysloglogger.h"
|
||||||
|
|
||||||
|
@ -27,15 +27,13 @@ vector<Object::Ptr> Object::m_HeldObjects;
|
|||||||
* Default constructor for the Object class.
|
* Default constructor for the Object class.
|
||||||
*/
|
*/
|
||||||
Object::Object(void)
|
Object::Object(void)
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor for the Object class.
|
* Destructor for the Object class.
|
||||||
*/
|
*/
|
||||||
Object::~Object(void)
|
Object::~Object(void)
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporarily holds onto a reference for an object. This can
|
* Temporarily holds onto a reference for an object. This can
|
||||||
|
@ -30,8 +30,8 @@ boost::mutex Process::m_Mutex;
|
|||||||
deque<Process::Ptr> Process::m_Tasks;
|
deque<Process::Ptr> Process::m_Tasks;
|
||||||
condition_variable Process::m_TasksCV;
|
condition_variable Process::m_TasksCV;
|
||||||
|
|
||||||
Process::Process(const string& command, const CompletionCallback& completionCallback)
|
Process::Process(const string& command)
|
||||||
: AsyncTask<Process, ProcessResult>(completionCallback), m_Command(command), m_UsePopen(false)
|
: AsyncTask<Process, ProcessResult>(), m_Command(command), m_UsePopen(false)
|
||||||
{
|
{
|
||||||
if (!m_ThreadCreated) {
|
if (!m_ThreadCreated) {
|
||||||
thread t(&Process::WorkerThreadProc);
|
thread t(&Process::WorkerThreadProc);
|
||||||
|
@ -39,7 +39,7 @@ public:
|
|||||||
|
|
||||||
static const int MaxTasksPerThread = 128;
|
static const int MaxTasksPerThread = 128;
|
||||||
|
|
||||||
Process(const string& command, const CompletionCallback& completionCallback);
|
Process(const string& command);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool m_ThreadCreated;
|
static bool m_ThreadCreated;
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
ScriptTask::ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments, CompletionCallback callback)
|
ScriptTask::ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments)
|
||||||
: AsyncTask<ScriptTask, Variant>(callback), m_Function(function), m_Arguments(arguments)
|
: AsyncTask<ScriptTask, Variant>(), m_Function(function), m_Arguments(arguments)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void ScriptTask::Run(void)
|
void ScriptTask::Run(void)
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
typedef shared_ptr<ScriptTask> Ptr;
|
typedef shared_ptr<ScriptTask> Ptr;
|
||||||
typedef weak_ptr<ScriptTask> WeakPtr;
|
typedef weak_ptr<ScriptTask> WeakPtr;
|
||||||
|
|
||||||
ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments, CompletionCallback callback);
|
ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Run(void);
|
virtual void Run(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user