Handout
This commit is contained in:
114
kernel/interrupt/guard.cc
Normal file
114
kernel/interrupt/guard.cc
Normal file
@@ -0,0 +1,114 @@
|
||||
/*! \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"
|
||||
|
||||
//! \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, 32> 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; }
|
||||
Reference in New Issue
Block a user