90 lines
2.8 KiB
C++
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
|