Allow fibers to be canceled while they're sleeping or blocked on promises
This commit is contained in:
parent
454573e048
commit
130da3623e
4 changed files with 48 additions and 1 deletions
|
|
@ -128,6 +128,7 @@ namespace fc {
|
|||
private:
|
||||
thread( class thread_d* );
|
||||
friend class promise_base;
|
||||
friend class task_base;
|
||||
friend class thread_d;
|
||||
friend class mutex;
|
||||
friend void* detail::get_thread_specific_data(unsigned slot);
|
||||
|
|
@ -154,8 +155,10 @@ namespace fc {
|
|||
|
||||
void async_task( task_base* t, const priority& p );
|
||||
void async_task( task_base* t, const priority& p, const time_point& tp );
|
||||
class thread_d* my;
|
||||
|
||||
void notify_task_has_been_canceled();
|
||||
|
||||
class thread_d* my;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ namespace fc {
|
|||
#ifndef NDEBUG
|
||||
_active_context->cancellation_reason = reason;
|
||||
#endif
|
||||
_active_context->ctx_thread->notify_task_has_been_canceled();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -418,6 +418,11 @@ namespace fc {
|
|||
return this == ¤t();
|
||||
}
|
||||
|
||||
void thread::notify_task_has_been_canceled()
|
||||
{
|
||||
async( [=](){ my->notify_task_has_been_canceled(); }, "notify_task_has_been_canceled", priority::max() );
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* support for providing a structured exception handler for async tasks */
|
||||
namespace detail
|
||||
|
|
|
|||
|
|
@ -606,5 +606,43 @@ namespace fc {
|
|||
iter->cleanup(iter->value);
|
||||
}
|
||||
|
||||
void notify_task_has_been_canceled()
|
||||
{
|
||||
for (fc::context** iter = &blocked; *iter;)
|
||||
{
|
||||
if ((*iter)->canceled)
|
||||
{
|
||||
fc::context* next_blocked = (*iter)->next_blocked;
|
||||
(*iter)->next_blocked = nullptr;
|
||||
ready_push_front(*iter);
|
||||
*iter = next_blocked;
|
||||
continue;
|
||||
}
|
||||
iter = &(*iter)->next_blocked;
|
||||
}
|
||||
|
||||
bool task_removed_from_sleep_pqueue = false;
|
||||
for (auto sleep_iter = sleep_pqueue.begin(); sleep_iter != sleep_pqueue.end();)
|
||||
{
|
||||
if ((*sleep_iter)->canceled)
|
||||
{
|
||||
bool already_on_ready_list = false;
|
||||
for (fc::context* ready_iter = ready_head; ready_iter; ready_iter = ready_iter->next)
|
||||
if (ready_iter == *sleep_iter)
|
||||
{
|
||||
already_on_ready_list = true;
|
||||
break;
|
||||
}
|
||||
if (!already_on_ready_list)
|
||||
ready_push_front(*sleep_iter);
|
||||
sleep_iter = sleep_pqueue.erase(sleep_iter);
|
||||
task_removed_from_sleep_pqueue = true;
|
||||
}
|
||||
else
|
||||
++sleep_iter;
|
||||
}
|
||||
if (task_removed_from_sleep_pqueue)
|
||||
std::make_heap(sleep_pqueue.begin(), sleep_pqueue.end(), sleep_priority_less());
|
||||
}
|
||||
};
|
||||
} // namespace fc
|
||||
|
|
|
|||
Loading…
Reference in a new issue