blob: a990e415cf6116f25fc1fb9e512336a5e0238369 [file] [log] [blame]
#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_exception)
{
// Received a second exception without delivering the first
// to a pending completion. Terminate using the first one.
try
{
std::rethrow_exception(std::exchange(pending_exception, {}));
}
catch (...)
{
std::terminate();
}
}
// If the scope is complete, get the pending completion, if it exists.
if (e || (pending_count == 0))
{
p = std::exchange(pending, nullptr);
}
// If we have an exception but no pending completion, save it away.
if (e && !p)
{
pending_exception = std::move(e);
}
}
if (p)
{
p->complete(std::move(e));
}
}
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_count == 0)
{
done = true;
}
else if (s.pending_exception)
{
e = std::exchange(s.pending_exception, {});
done = true;
}
else
{
s.pending = this;
}
}
if (done)
{
this->complete(std::move(e));
}
}
} // namespace scope_ns
} // namespace sdbusplus::async