
Synchronizes the kernel with interrupts using the Prologue/Epilogue ModelThe 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 a queue for each CPU, in which gate objects can be added. This is necessary if the critical section is occupied at the time an interrupt occurs, and the epilogue() method cannot be processed immediately. The queued epilogues are processed while leaving the critical section. More...
Functions | |
bool | active () |
Helper to check if we are currently in a guarded environment. More... | |
void | enter () |
Entering the critical section. More... | |
void | leave () |
Leaving the critical section. More... | |
void | relay (Gate *item) |
A prologue wants its epilogue to be processed. More... | |
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 a queue for each CPU, in which gate objects can be added. This is necessary if the critical section is occupied at the time an interrupt occurs, and the epilogue() method cannot be processed immediately. The queued epilogues are processed while leaving the critical section.
Hints:
The epilogue queue is a central data structure, whose consistency must be ensured. The implementation provided by the GateQueue may be not interrupt-transparent. Either you are able to implement a perfect interrupt-transparent queue yourself, or you simply disable interrupts during operations on the queue (hard synchronization).
In MPStuBS, 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 base. This must be prevented by using a Ticketlock to avoid concurrent execution of epilogues on other cores while inside the critical section. This giant lock should not be confused with the lock variable that marks the entry to the epilogue level!
Since Gate objects must not be enqueued multiple times in the same queue. So if two interrupts of the same type occur so quick (for MPStuBS: on the same core) that the corresponding epilogue has not yet been handled, you must not enqueue the same gate object again. The enqueue methods should prevent this.
bool Guard::active | ( | ) |
Helper to check if we are currently in a guarded environment.
true
if we are in epilogue level void Guard::enter | ( | ) |
Entering the critical section.
Entering the critical section has to be handled differently depending on the system: In a single-core system it is sufficient to mark the entry by just setting a lock variable (since only one control flow can enter the critical section at the same time). However, as soon as there are multiple cores, this is no longer the case. If a core wants to enter the critical section while another core is already in there, it should (actively) wait in this method until the critical area is released again.
void Guard::leave | ( | ) |
Leaving the critical section.
Leaves the critical section and processes the enqueued epilogues.
void Guard::relay | ( | Gate * | item | ) |
A prologue wants its epilogue to be processed.
This method is called by interrupt_handler if the previously executed Gate::prologue has returned true
– indicating that it needs its epilogue to be executed as well. Whether the epilogue is handled immediately or just enqueued to the epilogue queue depends on whether the critical section on this CPU is accessible or not.