RAII Guards

Relevant source files

This document describes the four RAII guard types provided by the kernel_guard crate: NoOp, IrqSave, NoPreempt, and NoPreemptIrqSave. These guards implement the Resource Acquisition Is Initialization (RAII) pattern to automatically manage critical sections by disabling interrupts and/or preemption when created and restoring the previous state when dropped.

For information about the underlying trait system that enables these guards, see Trait System. For architecture-specific implementations of interrupt control, see Multi-Architecture Support.

Overview

The RAII guards in kernel_guard provide automatic critical section management through Rust's ownership system. Each guard type disables specific kernel features upon creation and restores them when the guard goes out of scope, ensuring that critical sections are properly bounded even in the presence of early returns or panics.

Guard Type Hierarchy


Sources: src/lib.rs(L68 - L78)  src/lib.rs(L80 - L111)  src/lib.rs(L113 - L128) 

RAII Lifecycle Pattern

sequenceDiagram
    participant UserCode as "User Code"
    participant GuardStruct as "Guard Struct"
    participant BaseGuardacquire as "BaseGuard::acquire()"
    participant archlocal_irq_ as "arch::local_irq_*"
    participant KernelGuardIf as "KernelGuardIf"
    participant Dropdrop as "Drop::drop()"

    UserCode ->> GuardStruct: "new()"
    GuardStruct ->> BaseGuardacquire: "acquire()"
    alt IrqSave or NoPreemptIrqSave
        BaseGuardacquire ->> archlocal_irq_: "local_irq_save_and_disable()"
        archlocal_irq_ -->> BaseGuardacquire: "saved_flags: usize"
    end
    alt NoPreempt or NoPreemptIrqSave
        BaseGuardacquire ->> KernelGuardIf: "disable_preempt()"
    end
    BaseGuardacquire -->> GuardStruct: "state"
    GuardStruct -->> UserCode: "guard_instance"
    Note over UserCode: Critical section code runs
    UserCode ->> Dropdrop: "guard goes out of scope"
    Dropdrop ->> BaseGuardacquire: "release(state)"
    alt IrqSave or NoPreemptIrqSave
        BaseGuardacquire ->> archlocal_irq_: "local_irq_restore(state)"
    end
    alt NoPreempt or NoPreemptIrqSave
        BaseGuardacquire ->> KernelGuardIf: "enable_preempt()"
    end

Sources: src/lib.rs(L134 - L179)  src/lib.rs(L181 - L237) 

Guard Types

NoOp Guard

The NoOp guard provides a no-operation implementation that does nothing around critical sections. It serves as a placeholder when guard functionality is not needed or not available.

PropertyValue
State Type()
Target AvailabilityAll targets
IRQ ControlNone
Preemption ControlNone

The NoOp guard is always available and implements BaseGuard with empty operations:

// Implementation reference from src/lib.rs:113-117
impl BaseGuard for NoOp {
    type State = ();
    fn acquire() -> Self::State {}
    fn release(_state: Self::State) {}
}

Sources: src/lib.rs(L80 - L81)  src/lib.rs(L113 - L128) 

IrqSave Guard

The IrqSave guard disables local interrupts and saves the previous interrupt state, restoring it when dropped. This guard is only available on bare-metal targets (target_os = "none").

PropertyValue
State Typeusize(saved IRQ flags)
Target Availabilitytarget_os = "none"only
IRQ ControlSaves and disables, then restores
Preemption ControlNone

On non-bare-metal targets, IrqSave becomes a type alias to NoOp:

// Conditional compilation from src/lib.rs:83-111
cfg_if::cfg_if! {
    if #[cfg(any(target_os = "none", doc))] {
        pub struct IrqSave(usize);
    } else {
        pub type IrqSave = NoOp;
    }
}

The IrqSave implementation calls architecture-specific interrupt control functions:

Sources: src/lib.rs(L88)  src/lib.rs(L102 - L103)  src/lib.rs(L134 - L147)  src/lib.rs(L181 - L198) 

NoPreempt Guard

The NoPreempt guard disables kernel preemption for the duration of the critical section. It requires the preempt feature to be enabled and a user implementation of KernelGuardIf.

PropertyValue
State Type()
Target Availabilitytarget_os = "none"only
IRQ ControlNone
Preemption ControlDisables, then re-enables

The preemption control is conditional on the preempt feature:

// Feature-gated implementation from src/lib.rs:149-161
impl BaseGuard for NoPreempt {
    type State = ();
    fn acquire() -> Self::State {
        #[cfg(feature = "preempt")]
        crate_interface::call_interface!(KernelGuardIf::disable_preempt);
    }
    fn release(_state: Self::State) {
        #[cfg(feature = "preempt")]
        crate_interface::call_interface!(KernelGuardIf::enable_preempt);
    }
}

Sources: src/lib.rs(L92)  src/lib.rs(L105 - L106)  src/lib.rs(L149 - L161)  src/lib.rs(L200 - L218) 

NoPreemptIrqSave Guard

The NoPreemptIrqSave guard combines both preemption and interrupt control, providing the strongest level of critical section protection. It disables preemption first, then interrupts, and restores them in reverse order.

PropertyValue
State Typeusize(saved IRQ flags)
Target Availabilitytarget_os = "none"only
IRQ ControlSaves and disables, then restores
Preemption ControlDisables, then re-enables

The ordering ensures proper nesting: preemption is disabled before IRQs and re-enabled after IRQs are restored:

// Ordered disable/enable from src/lib.rs:163-179
impl BaseGuard for NoPreemptIrqSave {
    type State = usize;
    fn acquire() -> Self::State {
        // disable preempt first
        #[cfg(feature = "preempt")]
        crate_interface::call_interface!(KernelGuardIf::disable_preempt);
        // then disable IRQs
        super::arch::local_irq_save_and_disable()
    }
    fn release(state: Self::State) {
        // restore IRQs first
        super::arch::local_irq_restore(state);
        // then enable preempt
        #[cfg(feature = "preempt")]
        crate_interface::call_interface!(KernelGuardIf::enable_preempt);
    }
}

Sources: src/lib.rs(L100)  src/lib.rs(L108 - L109)  src/lib.rs(L163 - L179)  src/lib.rs(L220 - L237) 

Conditional Compilation Strategy

The guards use cfg_if macros to provide different implementations based on the target platform. This ensures that the crate can be used in both kernel and userspace contexts.

Target-Based Implementation Selection


Sources: src/lib.rs(L83 - L111)  src/lib.rs(L130 - L238) 

Usage Patterns

All guards follow the same basic usage pattern, differing only in their protection scope:

Guard TypeUse CaseDependencies
NoOpTesting, userspaceNone
IrqSaveInterrupt-safe critical sectionsArchitecture support
NoPreemptPreemption-safe critical sectionspreemptfeature +KernelGuardIfimpl
NoPreemptIrqSaveMaximum protection critical sectionsBoth above dependencies

The RAII pattern ensures automatic cleanup:

// Pattern from src/lib.rs:45-51
let guard = GuardType::new();
// Critical section automatically begins here
// ... critical section code ...
// Critical section automatically ends when guard is dropped

Sources: src/lib.rs(L12 - L19)  src/lib.rs(L45 - L51)  src/lib.rs(L181 - L237)