mirror of https://github.com/Icinga/icinga2.git
Bugfixes for the AsyncTask class.
This commit is contained in:
parent
310edc1074
commit
18bbde330c
|
@ -7,7 +7,6 @@ pkglib_LTLIBRARIES = \
|
|||
libbase_la_SOURCES = \
|
||||
application.cpp \
|
||||
application.h \
|
||||
asynctask.cpp \
|
||||
asynctask.h \
|
||||
component.cpp \
|
||||
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
|
||||
{
|
||||
|
||||
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.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
template<typename TClass, typename TResult>
|
||||
class AsyncTask : public AsyncTaskBase
|
||||
class AsyncTask : public Object
|
||||
{
|
||||
public:
|
||||
typedef shared_ptr<AsyncTask<TClass, TResult> > Ptr;
|
||||
|
@ -65,13 +39,39 @@ public:
|
|||
|
||||
/**
|
||||
* Constructor for the AsyncTask class.
|
||||
*
|
||||
* @param completionCallback Function that is called when the task is completed.
|
||||
*/
|
||||
AsyncTask(const CompletionCallback& completionCallback)
|
||||
: m_CompletionCallback(completionCallback)
|
||||
AsyncTask(void)
|
||||
: 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
|
||||
* the AsyncTask object.
|
||||
|
@ -89,21 +89,66 @@ public:
|
|||
if (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)
|
||||
{
|
||||
m_Result = result;
|
||||
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:
|
||||
/**
|
||||
* Used by the Finish method to proxy the completion callback into the main
|
||||
* thread. Invokes the completion callback and marks the task as finished.
|
||||
*/
|
||||
virtual void InvokeCompletionCallback(void)
|
||||
void InvokeCompletionCallback(void)
|
||||
{
|
||||
m_Finished = true;
|
||||
m_CompletionCallback(GetSelf());
|
||||
|
@ -113,8 +158,23 @@ private:
|
|||
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. */
|
||||
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>
|
||||
<ClCompile Include="application.cpp" />
|
||||
<ClCompile Include="asynctask.cpp" />
|
||||
<ClCompile Include="component.cpp" />
|
||||
<ClCompile Include="configobject.cpp" />
|
||||
<ClCompile Include="dictionary.cpp" />
|
||||
|
|
|
@ -85,9 +85,6 @@
|
|||
<ClCompile Include="scripttask.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asynctask.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="i2-base.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -210,8 +210,8 @@ ScriptTask::Ptr ConfigObject::InvokeHook(const string& hook,
|
|||
if (!func)
|
||||
throw invalid_argument("Function '" + funcName + "' does not exist.");
|
||||
|
||||
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments, callback);
|
||||
task->Start();
|
||||
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments);
|
||||
task->Start(callback);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
|
|
@ -167,6 +167,7 @@ using boost::system_time;
|
|||
#include "tcpclient.h"
|
||||
#include "tcpserver.h"
|
||||
#include "tlsclient.h"
|
||||
#include "logger.h"
|
||||
#include "asynctask.h"
|
||||
#include "process.h"
|
||||
#include "scriptfunction.h"
|
||||
|
@ -177,7 +178,6 @@ using boost::system_time;
|
|||
#include "application.h"
|
||||
#include "component.h"
|
||||
#include "threadpool.h"
|
||||
#include "logger.h"
|
||||
#include "streamlogger.h"
|
||||
#include "sysloglogger.h"
|
||||
|
||||
|
|
|
@ -27,15 +27,13 @@ vector<Object::Ptr> Object::m_HeldObjects;
|
|||
* Default constructor for the Object class.
|
||||
*/
|
||||
Object::Object(void)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Destructor for the Object class.
|
||||
*/
|
||||
Object::~Object(void)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/**
|
||||
* 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;
|
||||
condition_variable Process::m_TasksCV;
|
||||
|
||||
Process::Process(const string& command, const CompletionCallback& completionCallback)
|
||||
: AsyncTask<Process, ProcessResult>(completionCallback), m_Command(command), m_UsePopen(false)
|
||||
Process::Process(const string& command)
|
||||
: AsyncTask<Process, ProcessResult>(), m_Command(command), m_UsePopen(false)
|
||||
{
|
||||
if (!m_ThreadCreated) {
|
||||
thread t(&Process::WorkerThreadProc);
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
|
||||
static const int MaxTasksPerThread = 128;
|
||||
|
||||
Process(const string& command, const CompletionCallback& completionCallback);
|
||||
Process(const string& command);
|
||||
|
||||
private:
|
||||
static bool m_ThreadCreated;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
ScriptTask::ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments, CompletionCallback callback)
|
||||
: AsyncTask<ScriptTask, Variant>(callback), m_Function(function), m_Arguments(arguments)
|
||||
ScriptTask::ScriptTask(const ScriptFunction::Ptr& function, const vector<Variant>& arguments)
|
||||
: AsyncTask<ScriptTask, Variant>(), m_Function(function), m_Arguments(arguments)
|
||||
{ }
|
||||
|
||||
void ScriptTask::Run(void)
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
typedef shared_ptr<ScriptTask> Ptr;
|
||||
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:
|
||||
virtual void Run(void);
|
||||
|
|
Loading…
Reference in New Issue