Allow the user to supply a reason string when canceling a task (useful for debugging)

This commit is contained in:
Eric Frias 2014-08-27 14:07:44 -04:00
parent 8841f5e271
commit ac385d1f6b
10 changed files with 49 additions and 23 deletions

View file

@ -13,6 +13,13 @@
# define FC_TASK_NAME_DEFAULT_ARG = "?"
#endif
#define FC_CANCELATION_REASONS_ARE_MANDATORY 1
#ifdef FC_CANCELATION_REASONS_ARE_MANDATORY
# define FC_CANCELATION_REASON_DEFAULT_ARG
#else
# define FC_CANCELATION_REASON_DEFAULT_ARG = nullptr
#endif
namespace fc {
class abstract_thread;
struct void_t{};
@ -58,7 +65,7 @@ namespace fc {
const char* get_desc()const;
virtual void cancel();
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG);
bool canceled()const { return _canceled; }
bool ready()const;
bool error()const;
@ -91,6 +98,7 @@ namespace fc {
time_point _timeout;
fc::exception_ptr _exceptp;
bool _canceled;
const char* _cancellation_reason;
const char* _desc;
detail::completion_handler* _compl;
};
@ -210,14 +218,14 @@ namespace fc {
/// @pre valid()
bool error()const { return m_prom->error(); }
void cancel()const { if( m_prom ) m_prom->cancel(); }
void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) const { if( m_prom ) m_prom->cancel(reason); }
bool canceled()const { if( m_prom ) return m_prom->canceled(); else return true;}
void cancel_and_wait()
void cancel_and_wait(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG)
{
if( valid() )
{
cancel();
cancel(reason);
try
{
wait();
@ -276,9 +284,9 @@ namespace fc {
bool valid()const { return !!m_prom; }
bool canceled()const { return m_prom ? m_prom->canceled() : true; }
void cancel_and_wait()
void cancel_and_wait(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG)
{
cancel();
cancel(reason);
try
{
wait();
@ -294,7 +302,7 @@ namespace fc {
/// @pre valid()
bool error()const { return m_prom->error(); }
void cancel()const { if( m_prom ) m_prom->cancel(); }
void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) const { if( m_prom ) m_prom->cancel(reason); }
template<typename CompletionHandler>
void on_complete( CompletionHandler&& c ) {

View file

@ -30,7 +30,7 @@ namespace fc {
class task_base : virtual public promise_base {
public:
void run();
virtual void cancel() override;
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override;
protected:
~task_base();
@ -99,7 +99,7 @@ namespace fc {
_promise_impl = static_cast<promise<R>*>(this);
_run_functor = &detail::functor_run<FunctorType>::run;
}
virtual void cancel() override { task_base::cancel(); }
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
aligned<FunctorSize> _functor;
private:
@ -119,7 +119,7 @@ namespace fc {
_promise_impl = static_cast<promise<void>*>(this);
_run_functor = &detail::void_functor_run<FunctorType>::run;
}
virtual void cancel() override { task_base::cancel(); }
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
aligned<FunctorSize> _functor;
private:

View file

@ -82,7 +82,7 @@ namespace fc {
{
try
{
_rotation_task.cancel_and_wait();
_rotation_task.cancel_and_wait("file_appender is destructing");
}
catch( ... )
{

View file

@ -139,7 +139,7 @@ namespace fc
my->_ntp_thread.async([=](){
try
{
my->_request_time_task_done.cancel_and_wait();
my->_request_time_task_done.cancel_and_wait("ntp object is destructing");
}
catch ( const fc::exception& e )
{
@ -152,7 +152,7 @@ namespace fc
try
{
my->_read_loop_done.cancel();
my->_read_loop_done.cancel("ntp object is destructing");
my->_sock.close();
my->_read_loop_done.wait();
}

View file

@ -36,7 +36,7 @@ namespace fc {
~udt_epoll_service()
{
_epoll_loop.cancel();
_epoll_loop.cancel("udt_epoll_service is destructing");
_epoll_loop.wait();
UDT::cleanup();
}

View file

@ -243,7 +243,7 @@ namespace fc { namespace rpc {
{
if( my->_done.valid() && !my->_done.ready() )
{
my->_done.cancel();
my->_done.cancel("json_connection is destructing");
my->_out->close();
my->_done.wait();
}

View file

@ -48,6 +48,9 @@ namespace fc {
next(0),
ctx_thread(t),
canceled(false),
#ifndef NDEBUG
cancellation_reason(nullptr),
#endif
complete(false),
cur_task(0)
{
@ -78,6 +81,9 @@ namespace fc {
next(0),
ctx_thread(t),
canceled(false),
#ifndef NDEBUG
cancellation_reason(nullptr),
#endif
complete(false),
cur_task(0)
{}
@ -192,6 +198,9 @@ namespace fc {
fc::context* next;
fc::thread* ctx_thread;
bool canceled;
#ifndef NDEBUG
const char* cancellation_reason;
#endif
bool complete;
task_base* cur_task;
};

View file

@ -17,6 +17,9 @@ namespace fc {
#endif
_timeout(time_point::maximum()),
_canceled(false),
#ifndef NDEBUG
_cancellation_reason(nullptr),
#endif
_desc(desc),
_compl(nullptr)
{ }
@ -25,9 +28,12 @@ namespace fc {
return _desc;
}
void promise_base::cancel(){
void promise_base::cancel(const char* reason /* = nullptr */){
// wlog("${desc} canceled!", ("desc", _desc? _desc : ""));
_canceled = true;
#ifndef NDEBUG
_cancellation_reason = reason;
#endif
}
bool promise_base::ready()const {
return _ready;

View file

@ -54,12 +54,15 @@ namespace fc {
}
}
void task_base::cancel()
void task_base::cancel(const char* reason /* = nullptr */)
{
promise_base::cancel();
promise_base::cancel(reason);
if (_active_context)
{
_active_context->canceled = true;
#ifndef NDEBUG
_active_context->cancellation_reason = reason;
#endif
}
}

View file

@ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE( leave_mutex_locked )
fc::usleep(fc::seconds(1));
}, "test_task");
fc::usleep(fc::seconds(3));
test_task.cancel_and_wait();
test_task.cancel_and_wait("cancel called directly by test");
}
BOOST_TEST_PASSPOINT();
}
@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE( cancel_task_blocked_on_mutex)
}
fc::usleep(fc::seconds(3));
test_task.cancel_and_wait();
test_task.cancel_and_wait("cleaning up test");
}
}
@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE( cancel_an_active_task )
fc::usleep(fc::milliseconds(100));
BOOST_TEST_MESSAGE("Canceling task");
task.cancel();
task.cancel("canceling to test if cancel works");
try
{
task_result result = task.wait();
@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE( cleanup_cancelled_task )
BOOST_CHECK_MESSAGE(!weak_string_ptr.expired(), "Weak pointer should still be valid because async task should be holding the strong pointer");
fc::usleep(fc::milliseconds(100));
BOOST_TEST_MESSAGE("Canceling task");
task.cancel();
task.cancel("canceling to test if cancel works");
try
{
task.wait();
@ -181,7 +181,7 @@ BOOST_AUTO_TEST_CASE( cancel_scheduled_task )
simple_task();
simple_task();
fc::usleep(fc::seconds(4));
simple_task_done.cancel();
simple_task_done.cancel("canceling scheduled task to test if cancel works");
simple_task_done.wait();
}
catch ( const fc::exception& e )