async: match: stop pending sender on dtor
If the match is destructed with a pending Sender completion,
we need to 'stop' that Sender. We cannot 'complete' the Sender
because we do not have a message (dbus signal) associated with the
match, but if we do nothing then the Sender is hung (and leaked).
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: Ia6e465d46f0f7da08a385cf7c875bbda88a5ab61
diff --git a/test/async/context.cpp b/test/async/context.cpp
index 4092de5..fe273d1 100644
--- a/test/async/context.cpp
+++ b/test/async/context.cpp
@@ -13,21 +13,24 @@
ctx.reset();
}
+ void runToStop()
+ {
+ ctx->run(std::execution::just() |
+ std::execution::then([this]() { ctx->request_stop(); }));
+ }
+
std::optional<sdbusplus::async::context> ctx{std::in_place};
};
TEST_F(Context, RunSimple)
{
- ctx->run(std::execution::just() |
- std::execution::then([this]() { ctx->request_stop(); }));
+ runToStop();
}
TEST_F(Context, SpawnedTask)
{
ctx->spawn(std::execution::just());
-
- ctx->run(std::execution::just() |
- std::execution::then([this]() { ctx->request_stop(); }));
+ runToStop();
}
TEST_F(Context, SpawnDelayedTask)
@@ -41,8 +44,7 @@
ctx->spawn(sdbusplus::async::sleep_for(*ctx, timeout) |
std::execution::then([&ran]() { ran = true; }));
- ctx->run(std::execution::just() |
- std::execution::then([this]() { ctx->request_stop(); }));
+ runToStop();
auto stop = std::chrono::steady_clock::now();
@@ -50,3 +52,53 @@
EXPECT_GT(stop - start, timeout);
EXPECT_LT(stop - start, timeout * 2);
}
+
+TEST_F(Context, DestructMatcherWithPendingAwait)
+{
+ using namespace std::literals;
+
+ bool ran = false;
+ auto m = std::make_optional<sdbusplus::async::match>(
+ *ctx, sdbusplus::bus::match::rules::interfacesAdded(
+ "/this/is/a/bogus/path/for/SpawnMatcher"));
+
+ // Await the match completion (which will never happen).
+ ctx->spawn(m->next() | std::execution::then([&ran](...) { ran = true; }));
+
+ // Destruct the match.
+ ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
+ std::execution::then([&m](...) { m.reset(); }));
+
+ runToStop();
+
+ EXPECT_FALSE(ran);
+}
+
+TEST_F(Context, DestructMatcherWithPendingAwaitAsTask)
+{
+ using namespace std::literals;
+
+ auto m = std::make_optional<sdbusplus::async::match>(
+ *ctx, sdbusplus::bus::match::rules::interfacesAdded(
+ "/this/is/a/bogus/path/for/SpawnMatcher"));
+
+ struct _
+ {
+ static auto fn(decltype(m->next()) snd, bool& ran)
+ -> sdbusplus::async::task<>
+ {
+ co_await std::move(snd);
+ ran = true;
+ co_return;
+ }
+ };
+
+ bool ran = false;
+ ctx->spawn(_::fn(m->next(), ran));
+ ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
+ std::execution::then([&]() { m.reset(); }));
+
+ runToStop();
+
+ EXPECT_FALSE(ran);
+}