strat9_kernel/sync/preempt.rs
1//! Preemption guard — disables preemption for the lifetime of the guard.
2//!
3//! ## When to use
4//!
5//! Use `PreemptGuard` to protect **per-CPU data structures** that are only
6//! accessed from the CPU that owns them. Because no other CPU can touch
7//! them, a spin-lock is unnecessary — disabling preemption (so the current
8//! CPU cannot switch tasks mid-operation) is sufficient.
9//!
10//! ```rust,ignore
11//! let _guard = PreemptGuard::new();
12//! // safe to read/write per-CPU data here
13//! // guard is dropped at end of scope → preemption re-enabled
14//! ```
15//!
16//! ## What it does NOT protect
17//!
18//! `PreemptGuard` does **not** protect against concurrent access from other
19//! CPUs. For shared data, use [`crate::sync::SpinLock`] instead.
20//!
21//! ## Nesting
22//!
23//! Guards can be nested: each `PreemptGuard::new()` increments the per-CPU
24//! preemption depth and each `drop` decrements it. Preemption is re-enabled
25//! only when the depth reaches 0.
26
27use crate::arch::x86_64::percpu;
28
29/// RAII guard that disables preemption on the current CPU.
30///
31/// Preemption is restored when this value is dropped.
32#[must_use = "dropping a PreemptGuard immediately re-enables preemption"]
33pub struct PreemptGuard {
34 /// Marker to prevent Send — the guard must be dropped on the same CPU
35 /// it was created on.
36 _not_send: core::marker::PhantomData<*mut ()>,
37}
38
39impl PreemptGuard {
40 /// Disable preemption and return the guard.
41 #[inline]
42 pub fn new() -> Self {
43 percpu::preempt_disable();
44 PreemptGuard {
45 _not_send: core::marker::PhantomData,
46 }
47 }
48}
49
50impl Drop for PreemptGuard {
51 /// Performs the drop operation.
52 #[inline]
53 fn drop(&mut self) {
54 percpu::preempt_enable();
55 }
56}