async: context: simplify run function

Since we already have a `spawn` function to add async tasks,
get rid of the special "startup" task send to run.  Instead
users should pass the start up work to spawn and call run with
no parameters.

Eventually this will allow us to exit the run-loop for any and all
exceptions from the async context and potentially allow a caller
to re-enter the `run` loop after handling the child exception.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: Ia0e09a2493f0554538315d1d0c238aa11cb44e39
diff --git a/example/coroutine-example.cpp b/example/coroutine-example.cpp
index e3e8bec..725aa88 100644
--- a/example/coroutine-example.cpp
+++ b/example/coroutine-example.cpp
@@ -5,7 +5,7 @@
 #include <variant>
 #include <vector>
 
-auto runner(sdbusplus::async::context& ctx) -> sdbusplus::async::task<>
+auto startup(sdbusplus::async::context& ctx) -> sdbusplus::async::task<>
 {
     // Create a proxy to the systemd manager object.
     constexpr auto systemd = sdbusplus::async::proxy()
@@ -98,7 +98,8 @@
 int main()
 {
     sdbusplus::async::context ctx;
-    ctx.run(runner(ctx));
+    ctx.spawn(startup(ctx));
+    ctx.run();
 
     return 0;
 }
diff --git a/include/sdbusplus/async/context.hpp b/include/sdbusplus/async/context.hpp
index 3b971eb..12fc98c 100644
--- a/include/sdbusplus/async/context.hpp
+++ b/include/sdbusplus/async/context.hpp
@@ -24,9 +24,9 @@
  *
  *  This class encapsulates the run-loop for asynchronous operations,
  *  especially those using co-routines.  Primarily, the object is given
- *  a co-routine for the 'startup' processing of a daemon and it runs
- *  both the startup routine and any further asynchronous operations until
- *  the context is stopped.
+ *  co-routines (or Senders) for the processing, via `spawn`, and then the
+ *  object is `run` which handles all asynchronous operations until the
+ *  context is stopped, via `request_stop`.
  *
  *  The context has two threads:
  *      - The thread which called `run`, often from `main`, and named the
@@ -50,12 +50,8 @@
     // work.
     ~context() noexcept(false);
 
-    /** Run the loop.
-     *
-     *  @param[in] startup - The initialization operation to run.
-     */
-    template <execution::sender_of<execution::set_value_t()> Snd>
-    void run(Snd&& startup);
+    /** Run the loop. */
+    void run();
 
     /** Spawn a Sender to run on the context.
      *
@@ -114,33 +110,11 @@
     details::wait_process_completion* staged = nullptr;
     details::wait_process_completion* pending = nullptr;
 
-    void worker_run(task<> startup);
-    void caller_run(task<> startup);
+    void worker_run();
 
     static int dbus_event_handle(sd_event_source*, int, uint32_t, void*);
 };
 
-template <execution::sender_of<execution::set_value_t()> Snd>
-void context::run(Snd&& startup)
-{
-    // If Snd is a task, we can simply forward it on to the `caller_run`,
-    // but if it is a generic Sender we need to do a transformation first.
-    // In most cases, we expect users to use co-routines (ie. task<>).
-
-    if constexpr (std::is_same_v<task<>, std::decay_t<Snd>>)
-    {
-        caller_run(std::forward<Snd>(startup));
-    }
-    else
-    {
-        // Transform the generic sender into a task by a simple lambda.
-        caller_run([](Snd&& s) -> task<> {
-            co_await std::forward<Snd>(s);
-            co_return;
-        }(std::forward<Snd>(startup)));
-    }
-}
-
 namespace details
 {
 struct context_friend
diff --git a/src/async/context.cpp b/src/async/context.cpp
index 4807a6a..36f5552 100644
--- a/src/async/context.cpp
+++ b/src/async/context.cpp
@@ -148,12 +148,10 @@
     return first_stop;
 }
 
-void context::caller_run(task<> startup)
+void context::run()
 {
     // Start up the worker thread.
-    worker_thread = std::thread{[this, startup = std::move(startup)]() mutable {
-        worker_run(std::move(startup));
-    }};
+    worker_thread = std::thread{[this]() { worker_run(); }};
 
     // Run until the context requested to stop.
     while (!final_stop.stop_requested())
@@ -184,15 +182,9 @@
     }
 }
 
-void context::worker_run(task<> startup)
+void context::worker_run()
 {
-    // Begin the 'startup' task.
-    // This shouldn't start detached because we want to be able to forward
-    // failures back to the 'run'.  execution::ensure_started isn't
-    // implemented yet, so we don't have a lot of other options.
-    spawn(std::move(startup));
-
-    // Also start the sdbus 'wait/process' loop; treat it as an internal task.
+    // Start the sdbus 'wait/process' loop; treat it as an internal task.
     internal_tasks.spawn(details::wait_process_completion::loop(*this));
 
     // Run the execution::run_loop to handle all the tasks.
diff --git a/test/async/context.cpp b/test/async/context.cpp
index 39ee28d..34e5bb0 100644
--- a/test/async/context.cpp
+++ b/test/async/context.cpp
@@ -15,8 +15,9 @@
 
     void runToStop()
     {
-        ctx->run(std::execution::just() |
-                 std::execution::then([this]() { ctx->request_stop(); }));
+        ctx->spawn(std::execution::just() |
+                   std::execution::then([this]() { ctx->request_stop(); }));
+        ctx->run();
     }
 
     std::optional<sdbusplus::async::context> ctx{std::in_place};
diff --git a/test/async/timer.cpp b/test/async/timer.cpp
index f377e83..dfa95a6 100644
--- a/test/async/timer.cpp
+++ b/test/async/timer.cpp
@@ -14,8 +14,9 @@
 
     auto start = std::chrono::steady_clock::now();
 
-    ctx.run(sdbusplus::async::sleep_for(ctx, timeout) |
-            std::execution::then([&ctx]() { ctx.request_stop(); }));
+    ctx.spawn(sdbusplus::async::sleep_for(ctx, timeout) |
+              std::execution::then([&ctx]() { ctx.request_stop(); }));
+    ctx.run();
 
     auto stop = std::chrono::steady_clock::now();