blob: a990e415cf6116f25fc1fb9e512336a5e0238369 [file] [log] [blame]
Patrick Williams0139cac2022-09-20 17:04:17 -05001#include <sdbusplus/async/scope.hpp>
2
3#include <exception>
4
5namespace sdbusplus::async
6{
7scope::~scope() noexcept(false)
8{
Patrick Williamsc5b5ff52022-09-21 08:34:22 -05009 if (pending_count != 0)
Patrick Williams0139cac2022-09-20 17:04:17 -050010 {
11 throw std::logic_error(
12 "sdbusplus::async::scope destructed while tasks are pending.");
13 }
14}
15
16void scope::started_task() noexcept
17{
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050018 std::lock_guard l{lock};
Patrick Williams095eff82022-09-22 17:44:30 -050019 started = true;
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050020 ++pending_count;
Patrick Williams0139cac2022-09-20 17:04:17 -050021}
22
Patrick Williams4cfc2842022-09-22 09:53:33 -050023void scope::ended_task(std::exception_ptr&& e) noexcept
Patrick Williams0139cac2022-09-20 17:04:17 -050024{
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050025 scope_ns::scope_completion* p = nullptr;
26
27 {
28 std::lock_guard l{lock};
Patrick Williams4cfc2842022-09-22 09:53:33 -050029 --pending_count; // decrement count.
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050030
Patrick Williams4cfc2842022-09-22 09:53:33 -050031 if (e && pending_exception)
32 {
33 // Received a second exception without delivering the first
34 // to a pending completion. Terminate using the first one.
35 try
36 {
37 std::rethrow_exception(std::exchange(pending_exception, {}));
38 }
39 catch (...)
40 {
41 std::terminate();
42 }
43 }
44
45 // If the scope is complete, get the pending completion, if it exists.
46 if (e || (pending_count == 0))
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050047 {
48 p = std::exchange(pending, nullptr);
49 }
Patrick Williams4cfc2842022-09-22 09:53:33 -050050
51 // If we have an exception but no pending completion, save it away.
52 if (e && !p)
53 {
54 pending_exception = std::move(e);
55 }
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050056 }
57
58 if (p)
59 {
Patrick Williams4cfc2842022-09-22 09:53:33 -050060 p->complete(std::move(e));
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050061 }
Patrick Williams0139cac2022-09-20 17:04:17 -050062}
63
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050064scope_ns::scope_sender scope::empty() noexcept
65{
66 return scope_ns::scope_sender(*this);
67}
68
69namespace scope_ns
70{
71void scope_completion::arm() noexcept
72{
73 bool done = false;
Patrick Williams4cfc2842022-09-22 09:53:33 -050074 std::exception_ptr e{};
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050075
76 {
77 std::lock_guard l{s.lock};
Patrick Williams095eff82022-09-22 17:44:30 -050078 if (!s.started)
79 {
80 done = false;
81 }
82 else if (s.pending_count == 0)
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050083 {
84 done = true;
85 }
Patrick Williams4cfc2842022-09-22 09:53:33 -050086 else if (s.pending_exception)
87 {
88 e = std::exchange(s.pending_exception, {});
89 done = true;
90 }
Patrick Williamsc5b5ff52022-09-21 08:34:22 -050091 else
92 {
93 s.pending = this;
94 }
95 }
96
97 if (done)
98 {
Patrick Williams4cfc2842022-09-22 09:53:33 -050099 this->complete(std::move(e));
Patrick Williamsc5b5ff52022-09-21 08:34:22 -0500100 }
101}
102} // namespace scope_ns
103
Patrick Williams0139cac2022-09-20 17:04:17 -0500104} // namespace sdbusplus::async