Allow fibers to be canceled while they're sleeping or blocked on promises

This commit is contained in:
Eric Frias 2014-09-08 10:31:07 -04:00
parent 454573e048
commit 130da3623e
4 changed files with 48 additions and 1 deletions

View file

@ -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;
};
/**

View file

@ -69,6 +69,7 @@ namespace fc {
#ifndef NDEBUG
_active_context->cancellation_reason = reason;
#endif
_active_context->ctx_thread->notify_task_has_been_canceled();
}
}

View file

@ -418,6 +418,11 @@ namespace fc {
return this == &current();
}
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

View file

@ -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