mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Introduce the semantics of the atomic-mode guard
This commit is contained in:
parent
7a8afd8c48
commit
208d5aa62d
@ -16,10 +16,7 @@ cfg_if::cfg_if! {
|
|||||||
pub use set::{AtomicCpuSet, CpuSet};
|
pub use set::{AtomicCpuSet, CpuSet};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use crate::{
|
use crate::{arch::boot::smp::get_num_processors, cpu_local_cell, task::atomic_mode::InAtomicMode};
|
||||||
arch::boot::smp::get_num_processors, cpu_local_cell, task::DisabledPreemptGuard,
|
|
||||||
trap::DisabledLocalIrqGuard,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The ID of a CPU in the system.
|
/// The ID of a CPU in the system.
|
||||||
///
|
///
|
||||||
@ -125,13 +122,10 @@ pub fn current_cpu_racy() -> CpuId {
|
|||||||
CpuId(id)
|
CpuId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: When IRQs are disabled, the task cannot be passively preempted and
|
// SAFETY: A guard that enforces the atomic mode requires disabling any
|
||||||
// migrates to another CPU. If the task actively calls `yield`, it will not be
|
// context switching. So naturally, the current task is pinned on the CPU.
|
||||||
// successful either.
|
unsafe impl<T: InAtomicMode> PinCurrentCpu for T {}
|
||||||
unsafe impl PinCurrentCpu for DisabledLocalIrqGuard {}
|
unsafe impl PinCurrentCpu for dyn InAtomicMode + '_ {}
|
||||||
// SAFETY: When preemption is disabled, the task cannot be preempted and migrates
|
|
||||||
// to another CPU.
|
|
||||||
unsafe impl PinCurrentCpu for DisabledPreemptGuard {}
|
|
||||||
|
|
||||||
cpu_local_cell! {
|
cpu_local_cell! {
|
||||||
/// The number of the current CPU.
|
/// The number of the current CPU.
|
||||||
|
@ -45,3 +45,31 @@ pub fn might_sleep() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A marker trait for guard types that enforce the atomic mode.
|
||||||
|
///
|
||||||
|
/// Key kernel primitives such as `SpinLock` and `Rcu` rely on
|
||||||
|
/// [the atomic mode](crate::task::atomic_mode) for correctness or soundness.
|
||||||
|
/// The existence of such a guard guarantees that
|
||||||
|
/// the current task is executing in the atomic mode.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The implementer must ensure that the atomic mode is maintained while
|
||||||
|
/// the guard type is alive.
|
||||||
|
///
|
||||||
|
/// [`DisabledLocalIrqGuard`]: crate::task::DisabledPreemptGuard
|
||||||
|
/// [`DisabledPreemptGuard`]: crate::trap::DisabledLocalIrqGuard
|
||||||
|
pub unsafe trait InAtomicMode {}
|
||||||
|
|
||||||
|
/// Abstracts any type from which one can obtain a reference to an atomic-mode guard.
|
||||||
|
pub trait AsAtomicModeGuard {
|
||||||
|
/// Returns a guard for the atomic mode.
|
||||||
|
fn as_atomic_mode_guard(&self) -> &dyn InAtomicMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: InAtomicMode> AsAtomicModeGuard for G {
|
||||||
|
fn as_atomic_mode_guard(&self) -> &dyn InAtomicMode {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use crate::sync::GuardTransfer;
|
use crate::{sync::GuardTransfer, task::atomic_mode::InAtomicMode};
|
||||||
|
|
||||||
/// A guard for disable preempt.
|
/// A guard for disable preempt.
|
||||||
#[clippy::has_significant_drop]
|
#[clippy::has_significant_drop]
|
||||||
@ -13,6 +13,10 @@ pub struct DisabledPreemptGuard {
|
|||||||
|
|
||||||
impl !Send for DisabledPreemptGuard {}
|
impl !Send for DisabledPreemptGuard {}
|
||||||
|
|
||||||
|
// SAFETY: The guard disables preemptions, which meets the second
|
||||||
|
// sufficient condition for atomic mode.
|
||||||
|
unsafe impl InAtomicMode for DisabledPreemptGuard {}
|
||||||
|
|
||||||
impl DisabledPreemptGuard {
|
impl DisabledPreemptGuard {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
super::cpu_local::inc_guard_count();
|
super::cpu_local::inc_guard_count();
|
||||||
|
@ -6,6 +6,7 @@ use crate::{
|
|||||||
arch::irq::{self, IrqCallbackHandle, IRQ_ALLOCATOR},
|
arch::irq::{self, IrqCallbackHandle, IRQ_ALLOCATOR},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sync::GuardTransfer,
|
sync::GuardTransfer,
|
||||||
|
task::atomic_mode::InAtomicMode,
|
||||||
trap::TrapFrame,
|
trap::TrapFrame,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -140,6 +141,10 @@ pub struct DisabledLocalIrqGuard {
|
|||||||
|
|
||||||
impl !Send for DisabledLocalIrqGuard {}
|
impl !Send for DisabledLocalIrqGuard {}
|
||||||
|
|
||||||
|
// SAFETY: The guard disables local IRQs, which meets the first
|
||||||
|
// sufficient condition for atomic mode.
|
||||||
|
unsafe impl InAtomicMode for DisabledLocalIrqGuard {}
|
||||||
|
|
||||||
impl DisabledLocalIrqGuard {
|
impl DisabledLocalIrqGuard {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let was_enabled = irq::is_local_enabled();
|
let was_enabled = irq::is_local_enabled();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user