Fix cancellation bug in Choose class

This commit is contained in:
Markus Pilman 2023-12-08 17:46:21 +01:00
parent 3a04f8729d
commit a2bb520847
2 changed files with 49 additions and 2 deletions

View File

@ -1914,3 +1914,47 @@ TEST_CASE("/flow/coro/actor") {
co_await futureStreamTest();
co_await stackMemoryTest();
}
TEST_CASE("/flow/coro/chooseCancelWaiting") {
Promise<Void> voidPromise;
Promise<int> intPromise;
Future<Void> chooseFuture = Choose()
.When(voidPromise.getFuture(), [](const Void&) { ASSERT_ABORT(false); })
.When(intPromise.getFuture(), [](const int&) { ASSERT_ABORT(false); })
.run();
chooseFuture.cancel();
ASSERT(chooseFuture.getError().code() == error_code_actor_cancelled);
voidPromise.send(Void());
intPromise.sendError(end_of_stream());
ASSERT(chooseFuture.getError().code() == error_code_actor_cancelled);
return Void();
}
TEST_CASE("/flow/coro/chooseCancelReady") {
Promise<int> intPromise;
int res = 0;
Future<Void> chooseFuture = Choose().When(intPromise.getFuture(), [&](const int& val) { res = val; }).run();
intPromise.send(5);
ASSERT(chooseFuture.isReady());
ASSERT(res == 5);
chooseFuture.cancel();
ASSERT(chooseFuture.isReady());
return Void();
}
TEST_CASE("/flow/coro/chooseRepeatedCancel") {
Promise<Void> voidPromise;
Promise<int> intPromise;
Future<Void> chooseFuture = Choose()
.When(voidPromise.getFuture(), [](const Void&) { ASSERT_ABORT(false); })
.When(intPromise.getFuture(), [](const int&) { ASSERT_ABORT(false); })
.run();
chooseFuture.cancel();
ASSERT(chooseFuture.getError().code() == error_code_actor_cancelled);
chooseFuture.cancel();
ASSERT(chooseFuture.getError().code() == error_code_actor_cancelled);
voidPromise.sendError(end_of_stream());
intPromise.send(3);
ASSERT(chooseFuture.getError().code() == error_code_actor_cancelled);
return Void();
}

View File

@ -58,6 +58,7 @@ struct ChooseImplCallback<Parent, Idx, F, Args...>
}
void a_callback_fire(ThisCallback*, ValueType const& value) {
getParent()->actor_wait_state = 0;
getParent()->removeCallbacks();
try {
std::get<Idx>(getParent()->functions)(value);
@ -70,6 +71,7 @@ struct ChooseImplCallback<Parent, Idx, F, Args...>
}
void a_callback_error(ThisCallback*, Error e) {
getParent()->actor_wait_state = 0;
getParent()->removeCallbacks();
getParent()->SAV<Void>::sendErrorAndDelPromiseRef(e);
}
@ -103,12 +105,13 @@ struct ChooseImplActor final : Actor<Void>,
std::tuple<std::function<void(FutureReturnTypeT<Args> const&)>...>&& functions)
: Actor<Void>(), futures(futures), functions(functions) {
ChooseImplCallback<ChooseImplActor<Args...>, 0, Args...>::registerCallbacks();
actor_wait_state = 1;
}
void cancel() override {
auto waitState = actor_wait_state;
const auto waitState = actor_wait_state;
actor_wait_state = -1;
if (waitState) {
if (waitState > 0) {
ChooseImplCallback<ChooseImplActor<Args...>, 0, Args...>::removeCallbacks();
SAV<Void>::sendErrorAndDelPromiseRef(actor_cancelled());
}