Struct rstubs::interrupts::guard::Guard
source · pub struct Guard {
guarded: Ticket<Guarded>,
active: [AtomicBool; 4],
epilogues: UnsafeCell<[ArrayDeque<Epilogue, LEN>; 4]>,
}
Expand description
Synchronizes the kernel with interrupts using the Prologue/Epilogue Model
The Guard is used to synchronize between “normal” core activities (currently just the text output, later system calls) and interrupt handling routines. For this purpose, Guard has to contain one or more “queues”, in which Epilogue objects can be added. This is necessary if the critical section is occupied at the time when an interrupt occurs, and the Epilogue::run method cannot be executed immediately. The queued epilogues are processed when leaving the critical section.
The Guard protects and synchronizes various global kernel objects. These objects are only accessible when the guard is locked, by the control flow holding the lock. This prevents concurrent access and race conditions.
§Hints
The epilogue queue is a central data structure, whose consistency must be ensured. The implementation provided by the ArrayDeque is not safe against concurrency, i.e. there must never be accesses by two cores at the same time. You need to disable interrupts during operations on the queue.
For SMP, you need a separate epilogue queue for each core, in which each processor serializes its epilogues. However, epilogues on different cores could then be executed in parallel, since the critical section is managed separately on a per-core basis. This must be prevented by using a global Ticket lock to avoid concurrent execution of epilogues – there must never be more than one epilogue active on the whole system at the same time!
Please note: This giant lock (synchronizing all cores) should not be confused with the (core-specific) flag variable that marks only the entry to the epilogue level on the corresponding core!
Interrupts should be disabled for as short as possible. Due to this reason, the prologue/epilogue model allows epilogues to be interrupted by prologues. This means that interrupts should be enabled again before the epilogue is executed (this includes notifying the APIC about the “End-Of-Interrupt”)
Fields§
§guarded: Ticket<Guarded>
§active: [AtomicBool; 4]
Indicates whether the epilogue layer is active on the corresponding core
epilogues: UnsafeCell<[ArrayDeque<Epilogue, LEN>; 4]>
CPU-local queues for epilogues
Implementations§
source§impl Guard
impl Guard
pub const fn new() -> Self
fn epilogues(&self) -> &mut ArrayDeque<Epilogue, LEN>
sourcepub unsafe fn read(&self) -> &Guarded
pub unsafe fn read(&self) -> &Guarded
Temporary read-only access.
Safety: beware race conditions!
sourcepub fn enter(&self) -> GuardedGuard<'_>
pub fn enter(&self) -> GuardedGuard<'_>
Enter the epilogue layer or wait synchronously if it is already occupied.
A guard object is returned that unlocks the epilogue layer when it falls out of scope.