cppcoro icon indicating copy to clipboard operation
cppcoro copied to clipboard

Cancellation deadlock

Open apollo1321 opened this issue 5 months ago • 0 comments

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();

apollo1321 avatar Jan 23 '24 12:01 apollo1321