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.
| Property | Value |
|---|---|
| State Type | () |
| Target Availability | All targets |
| IRQ Control | None |
| Preemption Control | None |
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").
| Property | Value |
|---|---|
| State Type | usize(saved IRQ flags) |
| Target Availability | target_os = "none"only |
| IRQ Control | Saves and disables, then restores |
| Preemption Control | None |
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.
| Property | Value |
|---|---|
| State Type | () |
| Target Availability | target_os = "none"only |
| IRQ Control | None |
| Preemption Control | Disables, 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.
| Property | Value |
|---|---|
| State Type | usize(saved IRQ flags) |
| Target Availability | target_os = "none"only |
| IRQ Control | Saves and disables, then restores |
| Preemption Control | Disables, 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 Type | Use Case | Dependencies |
|---|---|---|
| NoOp | Testing, userspace | None |
| IrqSave | Interrupt-safe critical sections | Architecture support |
| NoPreempt | Preemption-safe critical sections | preemptfeature +KernelGuardIfimpl |
| NoPreemptIrqSave | Maximum protection critical sections | Both 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)