1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
//! RAII wrappers to create a critical section with local IRQs or preemption
//! disabled, used to implement spin locks in kernel.
//!
//! The critical section is created after the guard struct is created, and is
//! ended when the guard falls out of scope.
//!
//! Available guards:
//!
//! - [`NoOp`]: Does nothing around the critical section.
//! - [`IrqSave`]: Disables/enables local IRQs around the critical section.
//! - [`NoPreempt`]: Disables/enables kernel preemption around the critical
//! section.
//! - [`NoPreemptIrqSave`]: Disables/enables both kernel preemption and local
//! IRQs around the critical section.
//!
//! # Examples
//!
//! ```
//! let guard = NoPreempt::new();
//! /* The critical section starts here
//!
//! Do something that requires preemption to be disabled
//!
//! The critical section ends here */
//! drop(guard);
//! ```
#![no_std]
#![feature(asm_const)]
mod arch;
/// A base trait that all guards implement.
pub trait BaseGuard {
/// The saved state when entering the critical section.
type State: Clone + Copy;
/// Something that must be done before entering the critical section.
fn acquire() -> Self::State;
/// Something that must be done after leaving the critical section.
fn release(state: Self::State);
}
/// A no-op guard that does nothing around the critical section.
pub struct NoOp;
cfg_if::cfg_if! {
// For user-mode std apps, we use the alias of [`NoOp`] for all guards,
// since we can not disable IRQs or preemption in user-mode.
if #[cfg(any(target_os = "none", doc))] {
/// A guard that disables/enables local IRQs around the critical section.
pub struct IrqSave(usize);
/// A guard that disables/enables kernel preemption around the critical
/// section.
pub struct NoPreempt;
/// A guard that disables/enables both kernel preemption and local IRQs
/// around the critical section.
///
/// When entering the critical section, it disables kernel preemption
/// first, followed by local IRQs. When leaving the critical section, it
/// re-enables local IRQs first, followed by kernel preemption.
pub struct NoPreemptIrqSave(usize);
} else {
/// Alias of [`NoOp`].
pub type IrqSave = NoOp;
/// Alias of [`NoOp`].
pub type NoPreempt = NoOp;
/// Alias of [`NoOp`].
pub type NoPreemptIrqSave = NoOp;
}
}
impl BaseGuard for NoOp {
type State = ();
fn acquire() -> Self::State {}
fn release(_state: Self::State) {}
}
impl NoOp {
/// Creates a new [`NoOp`] guard.
pub const fn new() -> Self {
Self
}
}
impl Drop for NoOp {
fn drop(&mut self) {}
}
#[cfg(any(target_os = "none", doc))]
mod imp {
use super::*;
impl BaseGuard for IrqSave {
type State = usize;
#[inline]
fn acquire() -> Self::State {
super::arch::local_irq_save_and_disable()
}
#[inline]
fn release(state: Self::State) {
// restore IRQ states
super::arch::local_irq_restore(state);
}
}
impl BaseGuard for NoPreempt {
type State = ();
fn acquire() -> Self::State {
// disable preempt
#[cfg(feature = "preempt")]
// crate_interface::call_interface!(KernelGuardIf::disable_preempt);
taskctx::disable_preempt();
}
fn release(_state: Self::State) {
// enable preempt
#[cfg(feature = "preempt")]
// crate_interface::call_interface!(KernelGuardIf::enable_preempt);
taskctx::enable_preempt();
}
}
impl BaseGuard for NoPreemptIrqSave {
type State = usize;
fn acquire() -> Self::State {
// disable preempt
#[cfg(feature = "preempt")]
// crate_interface::call_interface!(KernelGuardIf::disable_preempt);
taskctx::disable_preempt();
// disable IRQs and save IRQ states
super::arch::local_irq_save_and_disable()
}
fn release(state: Self::State) {
// restore IRQ states
super::arch::local_irq_restore(state);
// enable preempt
#[cfg(feature = "preempt")]
// crate_interface::call_interface!(KernelGuardIf::enable_preempt);
taskctx::enable_preempt();
}
}
impl IrqSave {
/// Creates a new [`IrqSave`] guard.
pub fn new() -> Self {
Self(Self::acquire())
}
}
impl Drop for IrqSave {
fn drop(&mut self) {
Self::release(self.0)
}
}
impl Default for IrqSave {
fn default() -> Self {
Self::new()
}
}
impl NoPreempt {
/// Creates a new [`NoPreempt`] guard.
pub fn new() -> Self {
Self::acquire();
Self
}
}
impl Drop for NoPreempt {
fn drop(&mut self) {
Self::release(())
}
}
impl Default for NoPreempt {
fn default() -> Self {
Self::new()
}
}
impl NoPreemptIrqSave {
/// Creates a new [`NoPreemptIrqSave`] guard.
pub fn new() -> Self {
Self(Self::acquire())
}
}
impl Drop for NoPreemptIrqSave {
fn drop(&mut self) {
Self::release(self.0)
}
}
impl Default for NoPreemptIrqSave {
fn default() -> Self {
Self::new()
}
}
}