Allow the user to supply a reason string when canceling a task (useful for debugging)
This commit is contained in:
parent
8841f5e271
commit
ac385d1f6b
10 changed files with 49 additions and 23 deletions
|
|
@ -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 ) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ namespace fc {
|
|||
{
|
||||
try
|
||||
{
|
||||
_rotation_task.cancel_and_wait();
|
||||
_rotation_task.cancel_and_wait("file_appender is destructing");
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
Loading…
Reference in a new issue