Friedrich-Alexander-Universität Erlangen-Nürnberg  /   Technische Fakultät  /   Department Informatik
Assignment 3: Interrupt Synchronization using Prologue/Epilogue

The synchronization of activities within StuBS should be switched to the prologue/epilogue model. Modify your operating system in such a way that synchronization is no longer based solely on interrupt locks (hard synchronization).

For this purpose, you have to implement the Guard (and its wrapper Guarded), a GateQueue, and modify or extend Gate and the interrupt_handler.

Map of important classes for the third assignment

Of course, you also have to adapt your devices (e.g., Keyboard) and application accordingly, using the functions provided by Guard to protect all critical sections in the later case.

In MPStuBS, the Guard not only protects against interrupts, but also locks out other cores using a Ticketlock and thus prevents them from entering the critical section. Locked out cores have to wait actively until its their turn to enter the critical section, hence serializing the processing of critical sections.

Note
It might still be necessary to disable interrupts (hard synchronization) for a few instructions, e.g., when accessing GateQueue (a lock-free queue is not required nor recommended).

Learning Objectives

  • Protection of critical sections using the prolog/epilogue model

Videos (in German)

Characteristics

The Prologue

  • The prologue is called on external interrupts via the interrupt_handler().
  • The prologue should be as short as possible and only perform the most necessary tasks to handle the hardware which caused the interrupt. It should only share a minimal state with the rest of the system.
  • Using a prologue reduces interrupt latency throughout the system.
  • If necessary, a prologue requests an epilogue.

The Epilogue

  • The epilogue is executed after the prologue and is its causal consequence.
  • The system synchronizes the execution of epilogues on level ½. This means that there is only one control flow at level ½ at any time.
  • At level ½, interrupts are always active. Hence, prologues can occur.
  • Greedy execution of epilogues: If an epilogue can be executed, it will be executed. The level ½ will never be left if there are still epilogues left in the queue.
  • In MPStuBS, an epilogue is executed on the core where the corresponding prologue has taken place. Hence, each core will have its own epilogue queue.

Implementation Notes

  • Your GateQueue implementation should be based on a kind of linked list (in MPStuBS, its methods must first determine the proper list, depending on the core it is executed on).
  • Your test application should be quite similar to the one from assignment 2: Again, it should output the value of its increasing counter (for MPStuBS on each core at different positions) on the main window, while Keyboard::epilogue has a separate line for keystrokes.
  • The critical section should only be guarded using the prologue/epilogue model, hence making the Core::Interrupt::disable() and Core::Interrupt::enable() calls and the Spinlock (in MPStuBS) superfluous – remove them.
  • Since interrupts are automatically disabled in interrupt_handler(), they have to be manually enabled at a suitable point (before epilogues are processed).
  • You should use Ticketlock in MPStuBS to synchronize the cores and ensure a fair sequencing – due to the memory model, it is possible that some cores might starve when using Spinlock instead!

Extend serial interface (optional)

You can also switch the Serial interface to interrupt mode – in this case you should limit yourself to the receive interrupt. This allows you to receive inputs from keyboard and console at the same time, without having to implement non-blocking queries. Furthermore, this allows you to connect to the GDB_Stub anytime during runtime, interrupt the system at will (by pressing Ctrl-c in GDB) and, for example, read out the memory.