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:
|
private:
|
||||||
thread( class thread_d* );
|
thread( class thread_d* );
|
||||||
friend class promise_base;
|
friend class promise_base;
|
||||||
|
friend class task_base;
|
||||||
friend class thread_d;
|
friend class thread_d;
|
||||||
friend class mutex;
|
friend class mutex;
|
||||||
friend void* detail::get_thread_specific_data(unsigned slot);
|
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 );
|
||||||
void async_task( task_base* t, const priority& p, const time_point& tp );
|
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
|
#ifndef NDEBUG
|
||||||
_active_context->cancellation_reason = reason;
|
_active_context->cancellation_reason = reason;
|
||||||
#endif
|
#endif
|
||||||
|
_active_context->ctx_thread->notify_task_has_been_canceled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,11 @@ namespace fc {
|
||||||
return this == ¤t();
|
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
|
#ifdef _MSC_VER
|
||||||
/* support for providing a structured exception handler for async tasks */
|
/* support for providing a structured exception handler for async tasks */
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|
|
||||||
|
|
@ -606,5 +606,43 @@ namespace fc {
|
||||||
iter->cleanup(iter->value);
|
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
|
} // namespace fc
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue