You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
4.5 KiB
C++

/*! \file
* \brief \ref Guard synchronizes access to epilogue level
*/
#pragma once
#include "../object/bbuffer.h"
#include "../object/key.h"
#include "../types.h"
#include "epilogues.h"
#include "../device/textstream.h"
//! \brief The epilogue vault contains the protected data for the epilogue level
struct Vault {
Vault();
TextStream kout = TextStream(0, 80, 0, 10, true);
// no copy
Vault(const Vault&) = delete;
Vault& operator=(const Vault&) = delete;
};
/*! \brief Lock guard that provides access to the epilogue \ref Vault
*
* This object automatically unlocks the \ref Guard when it goes out of scope.
*/
class Guarded {
public:
//! This constructor should only be used by the \ref Guard
explicit Guarded(Vault& vault) : _vault(vault) {}
//! Leave the critical section
~Guarded();
//! Access the epilogue vault
Vault& vault() { return _vault; }
const Vault& vault() const { return _vault; }
// no copy
Guarded(const Guarded&) = delete;
Guarded& operator=(const Guarded&) = delete;
private:
Vault& _vault;
};
/*! \brief Synchronizes the kernel with interrupts using the Prologue/Epilogue
* Model \ingroup interrupts
*
* 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, \ref Guard has to contain one ore more \ref BBuffer
* "queues", in which \ref Epilogue functions can be added. This is necessary if
* the critical section is occupied at the time when an interrupt occurs, and
* the
* \ref Epilogue cannot be executed immediately. The queued epilogues are
* processed when leaving the critical section.
*
* **Hints:**
* - The epilogue queue is a central data structure, whose consistency
* must be ensured. The implementation provided by the \ref BBuffer is not
* entirely safe against concurrency. You need to disable
* interrupts during operations on the buffer.
* - 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 global \ref Ticketlock to avoid concurrent
* execution of epilogues -- there must never be more than one epilogue
* active on the whole system at the same time!<br>
* *Please note:* This [giant lock](https://en.wikipedia.org/wiki/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
* \ref Core::Interrupt::enable "enabled" again before the epilogue is
* executed (this includes notifying the APIC about the
* \ref LAPIC::endOfInterrupt() "End-Of-Interrupt")
*/
namespace Guard {
/*! \brief Entering the critical section from level 0.
*
* 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 flag 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.
*
* \todo(13) Implement Method
*/
Guarded enter();
/*! \brief Leaving the critical section.
*
* Leaves the critical section and processes all remaining (enqueued) epilogues.
* This may only be called while in level 1/2 after calling \ref enter().
*
* Note: Usually, this method is called by the destructor of the \ref
* Guarded.
*
* \todo(13) Implement Method
*/
void leave();
/*! \brief A prologue wants its epilogue to be processed (entering from level
* 1).
*
* This method is called by the interrupt handlers.
* Whether this is done immediately or the epilogue just enqueued to the
* epilogue queue depends on whether the critical section on *this* Core is
* accessible or not.
*
* \todo(13) Implement Method
*/
void relay(Epilogue handler);
/*! \brief Access the epilogue vault without taking the lock.
* Beware race conditions!
*/
const Vault& unsafeConstAccess();
} // namespace Guard