async: handle exceptions and stops

Add support in `context` and `scope` to handle exceptions and stop
conditions:

  * When an unhandled_stop occurs, turn it into an UnhandledStop
    exception.
  * When a `scope`-spawned task throws an exception, save it and cause
    `set_error` on the `scope::empty()`'s Receiver.
  * When anything in the `context` completes with `set_error` propagate
    that out to the caller of `context::run`.
  * If multiple exceptions occur within a `scope`, terminate.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I25285f7ece5c0675864489bbe1345fa8e7afa70c
diff --git a/test/async/context.cpp b/test/async/context.cpp
index fe273d1..9dea016 100644
--- a/test/async/context.cpp
+++ b/test/async/context.cpp
@@ -69,8 +69,7 @@
     ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
                std::execution::then([&m](...) { m.reset(); }));
 
-    runToStop();
-
+    EXPECT_THROW(runToStop(), sdbusplus::exception::UnhandledStop);
     EXPECT_FALSE(ran);
 }
 
@@ -98,7 +97,6 @@
     ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
                std::execution::then([&]() { m.reset(); }));
 
-    runToStop();
-
+    EXPECT_THROW(runToStop(), sdbusplus::exception::UnhandledStop);
     EXPECT_FALSE(ran);
 }