/*! \file * \brief Guard implementation */ #include "guard.h" #include "../arch/cache.h" #include "../arch/core.h" #include "../debug/assert.h" // IWYU pragma: keep #include "../debug/output.h" #include "../object/bbuffer.h" #include "epilogues.h" #include "../debug/copystream.h" //! \brief The protected data for the epilogue level static Vault global_vault; //! \brief State of the epilogue level (per core) struct State { //! \brief lists of pending epilogues BBuffer epilogue_queue; //! \brief indicates whether the epilogue level is entered bool epi_flag = false; } __attribute__((aligned(CACHE_LINE_SIZE))); constinit State state = {}; static inline State &get_state() { return state; } Vault::Vault() {} Guarded::~Guarded() { Guard::leave(); } Guarded Guard::enter() { assert(!get_state().epi_flag); // Mark entry of epilogue level on this core get_state().epi_flag = true; return Guarded(global_vault); } void Guard::leave() { // Make sure that we've performed an enter before. assert(get_state().epi_flag); Vault &vault = global_vault; bool status; while (true) { status = Core::Interrupt::disable(); // Get item from epilogue queue (if any) Epilogue iter; if (!get_state().epilogue_queue.consume(iter)) { break; } // Interrupts shall be restored before processing the epilogue Core::Interrupt::restore(status); // Process epilogue iter(vault); } // leave the epilogue level this core get_state().epi_flag = false; // Restore previous interrupt state Core::Interrupt::restore(status); } void Guard::relay(Epilogue handler) { if (get_state().epi_flag) { // Enqueue epilogue bool success = get_state().epilogue_queue.produce(handler); if (!success) DBG << "Dropped epilogue!" << endl; } else { // Mark entry of epilogue level on this core get_state().epi_flag = true; // Enable interrupts (interrupt_handler should already have sent the ACK // IRQ via LAPIC) Core::Interrupt::enable(); // We are, at this point, in the prologue level (E1), so this is // allowed: Vault &vault = global_vault; // Process epilogue handler(vault); // Make sure pending epilogues are executed while (true) { // Disable Interrupts while accessing the epilogue queue Core::Interrupt::disable(); Epilogue iter; if (!get_state().epilogue_queue.consume(iter)) { break; } // Interrupts shall be enabled before processing the epilogue Core::Interrupt::enable(); // Process epilogue iter(vault); } Core::Interrupt::disable(); // leave the epilogue level this core get_state().epi_flag = false; } } const Vault &Guard::unsafeConstAccess() { return global_vault; }