Handout
This commit is contained in:
29
sync/bellringer.cc
Normal file
29
sync/bellringer.cc
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "bellringer.h"
|
||||
|
||||
#include "../interrupt/guard.h"
|
||||
#include "../thread/thread.h"
|
||||
|
||||
struct Bell {
|
||||
// link pointer to the next bell in the bellringers bell list
|
||||
Bell *queue_link[1] = {nullptr};
|
||||
|
||||
Thread *thread;
|
||||
size_t counter;
|
||||
};
|
||||
|
||||
Bell **Bellringer::bell_link(Bell &obj, unsigned link_index) {
|
||||
return &obj.queue_link[link_index];
|
||||
}
|
||||
|
||||
// check: Checks whether bells are running out of time and rings them if
|
||||
// necessary
|
||||
void Bellringer::check(Vault &vault) { (void)vault; }
|
||||
|
||||
// job: Give a bell to the bellringer & ring it when the specified time ran out.
|
||||
void Bellringer::sleep(Vault &vault, unsigned int ms) {
|
||||
(void)vault;
|
||||
(void)ms;
|
||||
}
|
||||
|
||||
// Are there bells in the queue?
|
||||
bool Bellringer::bellPending() const { return false; }
|
||||
69
sync/bellringer.h
Normal file
69
sync/bellringer.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*! \file
|
||||
* \brief \ref Bellringer that manages and activates time-triggered activities.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../object/queue.h"
|
||||
#include "../types.h"
|
||||
|
||||
struct Vault;
|
||||
struct Bell;
|
||||
|
||||
/*! \brief Manages and activates time-triggered activities.
|
||||
* \ingroup ipc
|
||||
*
|
||||
* The Bellringer is regularly activated and checks whether any of the bells
|
||||
* should ring. The bells are stored in a Queue<Bell> that is managed by the
|
||||
* Bellringer. A clever implementation avoids iterating through the whole list
|
||||
* for every iteration by keeping the bells sorted and storing delta times. This
|
||||
* approach leads to a complexity of O(1) for the method called by the timer
|
||||
* interrupt in case no bells need to be rung.
|
||||
*/
|
||||
class Bellringer {
|
||||
// Prevent copies and assignments
|
||||
Bellringer(const Bellringer&) = delete;
|
||||
Bellringer& operator=(const Bellringer&) = delete;
|
||||
|
||||
/*! \brief List of bells currently managed.
|
||||
*
|
||||
* This list contains non-expired bells enqueued by job().
|
||||
* These bells will be checked on every call to check().
|
||||
*
|
||||
* All elements that should be inserted into a Queue instance
|
||||
* are required to be derived from Queue<Bell>::Node.
|
||||
*/
|
||||
Queue<Bell> bells;
|
||||
|
||||
//! Link pointer for bells
|
||||
static Bell** bell_link(Bell& obj, unsigned link_index);
|
||||
|
||||
public:
|
||||
// constructor
|
||||
Bellringer() : bells(0, bell_link) {}
|
||||
|
||||
/*! \brief Checks whether there are bells to be rung.
|
||||
*
|
||||
* Every call to check elapses a tick. Once such a tick reduces a bells
|
||||
* remaining time to zero, the bell will be rung.
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
*/
|
||||
void check(Vault& vault);
|
||||
|
||||
/*! \brief Passes a `bell` to the bellringer to be rung after `ms`
|
||||
* milliseconds.
|
||||
* \param bell Bell that should be rung after `ms` milliseconds
|
||||
* \param ms number of milliseconds that should be waited before
|
||||
* ringing the bell
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
*/
|
||||
void sleep(Vault& vault, unsigned int ms);
|
||||
|
||||
/*! \brief Checks whether there are enqueued bells.
|
||||
* \return true if there are enqueued bells, false otherwise
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
*/
|
||||
bool bellPending() const;
|
||||
};
|
||||
16
sync/semaphore.cc
Normal file
16
sync/semaphore.cc
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "./semaphore.h"
|
||||
|
||||
#include "../interrupt/guard.h"
|
||||
#include "../thread/thread.h"
|
||||
|
||||
Semaphore::Semaphore(unsigned c) { (void)c; }
|
||||
|
||||
Thread **Semaphore::thread_link(Thread &obj, unsigned link_index) {
|
||||
(void)obj;
|
||||
(void)link_index;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Semaphore::p(Vault &vault) { (void)vault; }
|
||||
|
||||
void Semaphore::v(Vault &vault) { (void)vault; }
|
||||
57
sync/semaphore.h
Normal file
57
sync/semaphore.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include "../object/queue.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \file
|
||||
* \brief \ref Semaphore for synchronization of threads.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \defgroup ipc Inter-Process Communication
|
||||
* \brief Communication between threads
|
||||
*/
|
||||
|
||||
// Forward declarations to break cyclic includes
|
||||
struct Vault;
|
||||
class Thread;
|
||||
|
||||
/*! \brief Semaphore used for synchronization of threads.
|
||||
* \ingroup ipc
|
||||
*
|
||||
* The class Semaphore implements the concept of counting semaphores.
|
||||
* The waiting list is provided by the base class Waitingroom.
|
||||
*/
|
||||
class Semaphore {
|
||||
// Prevent copies and assignments
|
||||
Semaphore(const Semaphore&) = delete;
|
||||
Semaphore& operator=(const Semaphore&) = delete;
|
||||
|
||||
static Thread** thread_link(Thread& obj, unsigned link_index);
|
||||
|
||||
public:
|
||||
/*! \brief Constructor; initialized the counter with provided value `c`
|
||||
* \param c Initial counter value
|
||||
*
|
||||
* \todo(16) Implement Constructor
|
||||
*/
|
||||
explicit Semaphore(unsigned c = 0);
|
||||
|
||||
/*! \brief Wait for access to the critical area.
|
||||
*
|
||||
* Enter/Wait operation: If the counter is greater than 0, then it is
|
||||
* decremented by one. Otherwise the calling thread will be enqueued
|
||||
* into the Waitingroom and marked as blocked.
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
*/
|
||||
void p(Vault& vault);
|
||||
|
||||
/*! \brief Leave the critical area.
|
||||
*
|
||||
* Leave operation: If there are threads in the Waitingroom, wake the
|
||||
* first one; otherwise increment the counter by one.
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
*/
|
||||
void v(Vault& vault);
|
||||
};
|
||||
60
sync/spinlock.h
Normal file
60
sync/spinlock.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*! \file
|
||||
* \brief Contains the class Spinlock
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Using Spinlocks, it is possible to serialize blocks of code
|
||||
* that might otherwise run in parallel on multiple CPU cores,
|
||||
* or be interleaved due to interrupts or scheduling.
|
||||
*
|
||||
* \ingroup sync
|
||||
*
|
||||
* Synchronization is implemented using a lock variable. Once a thread enters
|
||||
* the critical area, it sets the lock variable (to a non-zero value); when
|
||||
* this thread leaves the critical area, it resets the lock variable to zero.
|
||||
* Threads trying to enter an already locked critical area, actively wait,
|
||||
* continuously checking until the critical area is free again.
|
||||
*
|
||||
* Use the following two GCC intrinsics
|
||||
* - `bool __atomic_test_and_set(void *ptr, int memorder)`
|
||||
* - `void __atomic_clear (bool *ptr, int memorder)`
|
||||
*
|
||||
* These intrinsics are translated into atomic, architecture-specific
|
||||
* CPU instructions.
|
||||
*
|
||||
* If you want that things just work, choose __ATOMIC_SEQ_CST as memorder.
|
||||
* This is not the most efficient memory order but works reasonably well.
|
||||
*
|
||||
* <a
|
||||
* href="https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html">Atomic
|
||||
* Builtins in GCC manual</a>
|
||||
*/
|
||||
class Spinlock {
|
||||
// Prevent copies and assignments
|
||||
Spinlock(const Spinlock& copy) = delete;
|
||||
Spinlock& operator=(const Spinlock&) = delete;
|
||||
|
||||
public:
|
||||
/*! \brief Constructor; Initializes as unlocked.
|
||||
*
|
||||
* \todo(12) Complete Constructor (for \MPStuBS, or use \ref Ticketlock)
|
||||
*
|
||||
*/
|
||||
consteval Spinlock() {}
|
||||
|
||||
/*! \brief Enters the critical area. In case the area is already locked,
|
||||
* \ref lock() will actively wait until the area can be entered.
|
||||
*
|
||||
* \see \ref Core::pause()
|
||||
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
|
||||
*/
|
||||
void lock() {}
|
||||
|
||||
/*! \brief Unblocks the critical area.
|
||||
*
|
||||
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
|
||||
*/
|
||||
void unlock() {}
|
||||
};
|
||||
52
sync/ticketlock.h
Normal file
52
sync/ticketlock.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*! \file
|
||||
* \brief Contains the class Ticketlock
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \brief Using Ticketlocks, it is possible to serialize blocks of code
|
||||
* that might otherwise run in parallel on multiple CPU cores,
|
||||
* or be interleaved due to interrupts or scheduling.
|
||||
*
|
||||
* \ingroup sync
|
||||
*
|
||||
* Synchronization is implemented using a lock and a ticket variable.
|
||||
* Once a thread tries to enter the critical area, it obtains a ticket by
|
||||
* atomically incrementing the ticket variable and waiting until the lock
|
||||
* counter reaches this ticket, if it is not there already.
|
||||
* When a thread leaves the critical area, it increments the lock variable by
|
||||
* one and thereby allows the next thread to enter the critical area.
|
||||
*
|
||||
* If you want that things just work, choose __ATOMIC_SEQ_CST as memorder.
|
||||
* This is not the most efficient memory order but works reasonably well.
|
||||
*
|
||||
* <a
|
||||
* href="https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html">Atomic
|
||||
* Builtins in GCC manual</a>
|
||||
*/
|
||||
class Ticketlock {
|
||||
// Prevent copies and assignments
|
||||
Ticketlock(const Ticketlock& copy) = delete;
|
||||
Ticketlock& operator=(const Ticketlock&) = delete;
|
||||
|
||||
public:
|
||||
/*! \brief Constructor
|
||||
*
|
||||
* \todo(12) Complete Constructor (for \MPStuBS)
|
||||
*/
|
||||
consteval Ticketlock() {}
|
||||
|
||||
/*! \brief Enters the critical area. In case the area is already locked,
|
||||
* \ref lock() will actively wait until the area can be entered.
|
||||
*
|
||||
* \see \ref Core::pause()
|
||||
* \todo(12) Implement Method (for \MPStuBS)
|
||||
*/
|
||||
void lock() {}
|
||||
|
||||
/*! \brief Unblocks the critical area.
|
||||
*
|
||||
* \todo(12) Implement Method (for \MPStuBS)
|
||||
*/
|
||||
void unlock() {}
|
||||
};
|
||||
Reference in New Issue
Block a user