cmvr-es/cmvr-es/service/stop_all/include/stop_all_admission_gate.h

90 lines
2.8 KiB
C++

#ifndef CMVR_ES_STOP_ALL_ADMISSION_GATE_H
#define CMVR_ES_STOP_ALL_ADMISSION_GATE_H
#include <cstdint>
#include <mutex>
#include <unordered_set>
namespace cmvr::service {
// Provides the cross-domain admission boundary for SystemService::StopAll.
// Action and media coordinators may finish independently, but neither domain
// can admit new work until this gate is completed last.
class StopAllAdmissionGate final {
public:
struct FinishResult {
bool ticket_consumed{false};
bool admission_reopened{false};
};
struct StopAllTicket {
std::uint64_t generation{0};
std::uint64_t ticket_id{0};
bool valid() const noexcept
{
return generation != 0U && ticket_id != 0U;
}
};
class AdmissionGuard final {
public:
AdmissionGuard(AdmissionGuard&&) noexcept = default;
AdmissionGuard& operator=(AdmissionGuard&&) noexcept = default;
AdmissionGuard(const AdmissionGuard&) = delete;
AdmissionGuard& operator=(const AdmissionGuard&) = delete;
bool accepting() const noexcept { return accepting_; }
std::uint64_t generation() const noexcept { return generation_; }
private:
friend class StopAllAdmissionGate;
AdmissionGuard(
std::unique_lock<std::mutex>&& lock,
bool accepting,
std::uint64_t generation) noexcept;
std::unique_lock<std::mutex> lock_;
bool accepting_{false};
std::uint64_t generation_{0};
};
// The returned guard linearizes a bounded admission operation against
// beginStopAll(). Do not retain it while executing device work.
AdmissionGuard lockAdmission();
// Concurrent callers join one round. A failed round remains closed until
// a later StopAll round successfully confirms every domain is stopped.
StopAllTicket beginStopAll();
bool finishStopAll(
const StopAllTicket& ticket,
bool all_domains_stop_confirmed);
// Consumes one participant ticket and reports whether the complete round
// actually reopened admission. A participant can confirm its own work
// while another participant has failed or is still outstanding.
FinishResult finishStopAllDetailed(
const StopAllTicket& ticket,
bool all_domains_stop_confirmed);
// Test/process teardown hook. Runtime code must recover a failed gate with
// a new successful StopAll round instead of bypassing fail-closed state.
void clearForTesting() noexcept;
private:
std::mutex mutex_;
bool accepting_{true};
bool stop_all_failed_{false};
std::uint64_t generation_{1U};
std::uint64_t next_ticket_id_{0U};
std::unordered_set<std::uint64_t> outstanding_tickets_;
};
StopAllAdmissionGate& globalStopAllAdmissionGate();
} // namespace cmvr::service
#endif // CMVR_ES_STOP_ALL_ADMISSION_GATE_H