Struct rstubs::interrupts::guard::Guard

source ·
pub struct Guard {
    guarded: Ticket<Guarded>,
    local: [UnsafeCell<Align<Local>>; 1],
}
Expand description

Synchronizes the kernel with interrupts using the Prolog/Epilog 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 ore more “queues”, in which Epilog objects can be added. This is necessary if the critical section is occupied at the time when an interrupt occurs, and the Epilog::run method cannot be executed immediately. The queued epilogs are processed when leaving the critical section.

The Guard protects and synchronizes various global kernel objects. These object are only accessible when the guard is locked, by the control flow holding the lock. This prevents concurrent access and race conditions.

§Hints

The epilog 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 epilog queue for each core, in which each processor serializes its epilogs. However, epilogs 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 Ticket lock to avoid concurrent execution of epilogs – there must never be more than one epilog 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 epilog level on the corresponding core!

Interrupts should be disabled for as short as possible. Due to this reason, the prologue/epilog model allows epilogs to be interrupted by prologues. This means that interrupts should be int::enable “enabled” again before the epilog is executed (this includes notifying the APIC about the “End-Of-Interrupt”)

Fields§

§guarded: Ticket<Guarded>§local: [UnsafeCell<Align<Local>>; 1]

Safety: The local data is only accessed by the corresponding core, preventing race condition.

Implementations§

source§

impl Guard

source

pub const fn new() -> Self

source

fn local(&self) -> &mut Local

source

pub unsafe fn read(&self) -> &Guarded

Temporary read-only access.

Safety: beware race conditions!

source

pub unsafe fn get(&self) -> &mut Guarded

Temporary mutable access, which only succeeds if the current thread has already locked the guard.

Safety: beware race conditions!

source

pub fn enter(&self) -> GuardKey<'_>

Enter the epilog layer or wait synchronously if it is already occupied.

A guard object is returned that unlocks the epilog layer when it falls out of scope.

source

pub fn relay(&self, epilog: Epilog)

Register the given epilog, which is either executed directly if possible or it is enqueued for later execution.

source

pub fn leave(&self)

Leave the epilog layer.

source

pub fn active(&self) -> bool

Returns wether the layer 1/2 is active

source

pub fn run<R>(&self, f: impl FnOnce(&mut Guarded) -> R) -> R

Enters layer 1/2, runs f, and leaves

Trait Implementations§

source§

impl Sync for Guard

Auto Trait Implementations§

§

impl !RefUnwindSafe for Guard

§

impl Send for Guard

§

impl Unpin for Guard

§

impl !UnwindSafe for Guard

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.