cppcoro
cppcoro copied to clipboard
Cancellation deadlock
The following code reproduces cancellation deadlock. I understand the essence of the problem, if anyone is interested, I would be happy to discuss it. Also, I have studied the facebook/folly code, there is no such problem, since in-place executors are not allowed for stackless coroutines. It seems to me that this problem might be quite general. I did not find any mention of it in the std::execution proposal and in the P2175R0 paper, and do not fully understand how it deals with it.
#include "doctest/doctest.h"
#include <cppcoro/cancellation_registration.hpp>
#include <cppcoro/cancellation_source.hpp>
#include <cppcoro/single_consumer_event.hpp>
#include <cppcoro/static_thread_pool.hpp>
#include <cppcoro/sync_wait.hpp>
#include <cppcoro/task.hpp>
#include <cppcoro/when_all.hpp>
#include <chrono>
#include <thread>
TEST_SUITE_BEGIN("cancellation with events tests");
TEST_CASE("check deadlock freedom for events in cancellation callbacks")
{
cppcoro::static_thread_pool threadPool(3);
for (int i = 0; i < 20000; ++i)
{
cppcoro::single_consumer_event event1;
cppcoro::single_consumer_event event2;
cppcoro::cancellation_source source1;
cppcoro::cancellation_source source2;
auto coro1 = [&]() -> cppcoro::task<void> {
auto guard =
cppcoro::cancellation_registration(source1.token(), [&]() { event2.set(); });
co_await event1;
};
auto coro2 = [&]() -> cppcoro::task<void> {
auto guard =
cppcoro::cancellation_registration(source2.token(), [&]() { event1.set(); });
co_await event2;
};
auto cancelCoro1 = [&]() -> cppcoro::task<void> {
co_await threadPool.schedule();
source1.request_cancellation();
};
auto cancelCoro2 = [&]() -> cppcoro::task<void> {
co_await threadPool.schedule();
source2.request_cancellation();
};
auto fallbackCoro = [&]() -> cppcoro::task<void> {
co_await threadPool.schedule();
std::this_thread::sleep_for(std::chrono::microseconds(10));
event1.set();
event2.set();
};
cppcoro::sync_wait(
cppcoro::when_all(coro1(), coro2(), cancelCoro1(), cancelCoro2(), fallbackCoro()));
}
}
TEST_SUITE_END();