async: switch to stdexec async_scope
Use the `async_scope` implementation from stdexec instead of the
custom `scope` class here, which greatly reduces our own code and
also aligns better with the C++ STL direction. The major changes are
around exception paths:
- Spawned tasks which end with an exception will now std::terminate,
so any task expected to throw should have an `upon_error` chain.
- Spawned tasks which are stopped will be no longer throw an
`UnexpectedStop` exception, so they should be chained with an
`upon_stopped` if this is important.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I4e0c85712652efa5b296b898dcc2b0026ba4c625
diff --git a/src/async/context.cpp b/src/async/context.cpp
index 1da888c..85e0200 100644
--- a/src/async/context.cpp
+++ b/src/async/context.cpp
@@ -39,7 +39,10 @@
context& ctx;
event_t::time_resolution timeout{};
- static task<> loop(context& ctx);
+ // TODO: It seems like we should be able to do a normal `task<>` here
+ // but spawn on it compile fails.
+ static exec::basic_task<void, exec::__task::__raw_task_context<void>>
+ loop(context& ctx);
static void wait_once(context& ctx);
};
@@ -99,7 +102,8 @@
context& ctx;
};
-task<> wait_process_completion::loop(context& ctx)
+exec::basic_task<void, exec::__task::__raw_task_context<void>>
+ wait_process_completion::loop(context& ctx)
{
while (!ctx.final_stop.stop_requested())
{
@@ -142,10 +146,7 @@
wait_for_wait_process_stopped();
// Wait for all the internal tasks to complete.
- stdexec::sync_wait(internal_tasks.empty() |
- execution::upon_error([&](auto&& e) {
- pending_exceptions.emplace_back(std::move(e));
- }));
+ stdexec::sync_wait(internal_tasks.on_empty());
// Finish up the loop and join the thread.
// (There shouldn't be anything going on by this point anyhow.)
@@ -162,8 +163,7 @@
void context::worker_run()
{
// Start the sdbus 'wait/process' loop; treat it as an internal task.
- internal_tasks.spawn(details::wait_process_completion::loop(*this) |
- execution::upon_stopped([]() {}));
+ internal_tasks.spawn(details::wait_process_completion::loop(*this));
// Run the execution::run_loop to handle all the tasks.
loop.run();
@@ -212,11 +212,8 @@
}
// Spawn the watch for completion / exceptions.
- internal_tasks.spawn(pending_tasks.empty() |
- execution::then([this]() { spawn_complete(); }) |
- execution::upon_error([this](auto&& e) {
- spawn_complete(std::move(e));
- }));
+ internal_tasks.spawn(pending_tasks.on_empty() |
+ execution::then([this]() { spawn_complete(); }));
}
void context::caller_run()
diff --git a/src/async/scope.cpp b/src/async/scope.cpp
deleted file mode 100644
index d9eb8a7..0000000
--- a/src/async/scope.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include <sdbusplus/async/scope.hpp>
-
-#include <exception>
-
-namespace sdbusplus::async
-{
-scope::~scope() noexcept(false)
-{
- if (pending_count != 0)
- {
- throw std::logic_error(
- "sdbusplus::async::scope destructed while tasks are pending.");
- }
-}
-
-void scope::started_task() noexcept
-{
- std::lock_guard l{lock};
- started = true;
- ++pending_count;
-}
-
-void scope::ended_task(std::exception_ptr&& e) noexcept
-{
- scope_ns::scope_completion* p = nullptr;
-
- {
- std::lock_guard l{lock};
- --pending_count; // decrement count.
-
- if (e)
- {
- pending_exceptions.emplace_back(std::exchange(e, {}));
- }
-
- // If the scope is complete, get the pending completion, if it exists.
- if (!pending_exceptions.empty() || (pending_count == 0))
- {
- p = std::exchange(pending, nullptr);
- }
- }
-
- if (p)
- {
- std::exception_ptr fwd_exception = {};
- if (!pending_exceptions.empty())
- {
- fwd_exception = pending_exceptions.front();
- pending_exceptions.pop_front();
- }
- p->complete(std::move(fwd_exception));
- }
-}
-
-scope_ns::scope_sender scope::empty() noexcept
-{
- return scope_ns::scope_sender(*this);
-}
-
-namespace scope_ns
-{
-void scope_completion::arm() noexcept
-{
- bool done = false;
- std::exception_ptr e{};
-
- {
- std::lock_guard l{s.lock};
- if (!s.started)
- {
- done = false;
- }
- else if (!s.pending_exceptions.empty())
- {
- e = s.pending_exceptions.front();
- s.pending_exceptions.pop_front();
- done = true;
- }
- else if (s.pending_count == 0)
- {
- done = true;
- }
- else
- {
- s.pending = this;
- }
- }
-
- if (done)
- {
- this->complete(std::move(e));
- }
-}
-} // namespace scope_ns
-
-} // namespace sdbusplus::async