Bind spin semantics to Guardian

This commit is contained in:
Chen Chengjun 2025-03-25 22:08:26 +08:00 committed by Ruihan Li
parent 208d5aa62d
commit a77e653db6
4 changed files with 93 additions and 53 deletions

View File

@ -1,16 +1,18 @@
// SPDX-License-Identifier: MPL-2.0
use crate::{
task::{disable_preempt, DisabledPreemptGuard},
task::{atomic_mode::AsAtomicModeGuard, disable_preempt, DisabledPreemptGuard},
trap::{disable_local, DisabledLocalIrqGuard},
};
/// A guardian that denotes the guard behavior for holding a lock.
pub trait Guardian {
/// The guard type for holding a spin lock or a write lock.
type Guard: GuardTransfer;
/// The guard type for holding a read lock.
type ReadGuard: GuardTransfer;
/// A guardian that denotes the guard behavior for holding a spin-based lock.
///
/// It at least ensures that the atomic mode is maintained while the lock is held.
pub trait SpinGuardian {
/// The guard type for holding a spin lock or a spin-based write lock.
type Guard: AsAtomicModeGuard + GuardTransfer;
/// The guard type for holding a spin-based read lock.
type ReadGuard: AsAtomicModeGuard + GuardTransfer;
/// Creates a new guard.
fn guard() -> Self::Guard;
@ -32,7 +34,7 @@ pub trait GuardTransfer {
/// A guardian that disables preemption while holding a lock.
pub struct PreemptDisabled;
impl Guardian for PreemptDisabled {
impl SpinGuardian for PreemptDisabled {
type Guard = DisabledPreemptGuard;
type ReadGuard = DisabledPreemptGuard;
@ -53,7 +55,7 @@ impl Guardian for PreemptDisabled {
/// context, then it is ok not to use this guardian in the process context.
pub struct LocalIrqDisabled;
impl Guardian for LocalIrqDisabled {
impl SpinGuardian for LocalIrqDisabled {
type Guard = DisabledLocalIrqGuard;
type ReadGuard = DisabledLocalIrqGuard;
@ -79,7 +81,7 @@ impl Guardian for LocalIrqDisabled {
/// [`SpinLock`]: super::SpinLock
pub struct WriteIrqDisabled;
impl Guardian for WriteIrqDisabled {
impl SpinGuardian for WriteIrqDisabled {
type Guard = DisabledLocalIrqGuard;
type ReadGuard = DisabledPreemptGuard;

View File

@ -10,6 +10,7 @@ use crate::{
cpu::{AtomicCpuSet, CpuId, CpuSet, PinCurrentCpu},
prelude::*,
sync::SpinLock,
task::atomic_mode::AsAtomicModeGuard,
};
/// A RCU monitor ensures the completion of _grace periods_ by keeping track
@ -42,7 +43,7 @@ impl RcuMonitor {
// GP.
let callbacks = {
let mut state = self.state.disable_irq().lock();
let cpu = state.guard().current_cpu();
let cpu = state.as_atomic_mode_guard().current_cpu();
if state.current_gp.is_complete() {
return;
}

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0
#![expect(dead_code)]
use alloc::sync::Arc;
use core::{
cell::UnsafeCell,
@ -15,9 +13,10 @@ use core::{
};
use super::{
guard::{GuardTransfer, Guardian},
guard::{GuardTransfer, SpinGuardian},
PreemptDisabled,
};
use crate::task::atomic_mode::AsAtomicModeGuard;
/// Spin-based Read-write Lock
///
@ -125,7 +124,7 @@ impl<T, G> RwLock<T, G> {
}
}
impl<T: ?Sized, G: Guardian> RwLock<T, G> {
impl<T: ?Sized, G: SpinGuardian> RwLock<T, G> {
/// Acquires a read lock and spin-wait until it can be acquired.
///
/// The calling thread will spin-wait until there are no writers or
@ -360,29 +359,29 @@ impl<T: ?Sized + fmt::Debug, G> fmt::Debug for RwLock<T, G> {
unsafe impl<T: ?Sized + Send, G> Send for RwLock<T, G> {}
unsafe impl<T: ?Sized + Send + Sync, G> Sync for RwLock<T, G> {}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> !Send
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> !Send
for RwLockWriteGuard_<T, R, G>
{
}
unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G: Guardian> Sync
unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G: SpinGuardian> Sync
for RwLockWriteGuard_<T, R, G>
{
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> !Send
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> !Send
for RwLockReadGuard_<T, R, G>
{
}
unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G: Guardian> Sync
unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G: SpinGuardian> Sync
for RwLockReadGuard_<T, R, G>
{
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> !Send
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> !Send
for RwLockUpgradeableGuard_<T, R, G>
{
}
unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G: Guardian> Sync
unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G: SpinGuardian> Sync
for RwLockUpgradeableGuard_<T, R, G>
{
}
@ -390,18 +389,26 @@ unsafe impl<T: ?Sized + Sync, R: Deref<Target = RwLock<T, G>> + Clone + Sync, G:
/// A guard that provides immutable data access.
#[clippy::has_significant_drop]
#[must_use]
pub struct RwLockReadGuard_<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> {
pub struct RwLockReadGuard_<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> {
guard: G::ReadGuard,
inner: R,
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> AsAtomicModeGuard
for RwLockReadGuard_<T, R, G>
{
fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
self.guard.as_atomic_mode_guard()
}
}
/// A guard that provides shared read access to the data protected by a [`RwLock`].
pub type RwLockReadGuard<'a, T, G> = RwLockReadGuard_<T, &'a RwLock<T, G>, G>;
/// A guard that provides shared read access to the data protected by a `Arc<RwLock>`.
pub type ArcRwLockReadGuard<T, G> = RwLockReadGuard_<T, Arc<RwLock<T, G>>, G>;
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Deref
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Deref
for RwLockReadGuard_<T, R, G>
{
type Target = T;
@ -411,7 +418,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Deref
}
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Drop
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Drop
for RwLockReadGuard_<T, R, G>
{
fn drop(&mut self) {
@ -419,7 +426,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Drop
}
}
impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> fmt::Debug
impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> fmt::Debug
for RwLockReadGuard_<T, R, G>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -428,17 +435,25 @@ impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardia
}
/// A guard that provides mutable data access.
pub struct RwLockWriteGuard_<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> {
pub struct RwLockWriteGuard_<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> {
guard: G::Guard,
inner: R,
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> AsAtomicModeGuard
for RwLockWriteGuard_<T, R, G>
{
fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
self.guard.as_atomic_mode_guard()
}
}
/// A guard that provides exclusive write access to the data protected by a [`RwLock`].
pub type RwLockWriteGuard<'a, T, G> = RwLockWriteGuard_<T, &'a RwLock<T, G>, G>;
/// A guard that provides exclusive write access to the data protected by a `Arc<RwLock>`.
pub type ArcRwLockWriteGuard<T, G> = RwLockWriteGuard_<T, Arc<RwLock<T, G>>, G>;
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Deref
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Deref
for RwLockWriteGuard_<T, R, G>
{
type Target = T;
@ -448,7 +463,9 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Deref
}
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> RwLockWriteGuard_<T, R, G> {
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian>
RwLockWriteGuard_<T, R, G>
{
/// Atomically downgrades a write guard to an upgradeable reader guard.
///
/// This method always succeeds because the lock is exclusively held by the writer.
@ -479,7 +496,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> RwLockWrit
}
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> DerefMut
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> DerefMut
for RwLockWriteGuard_<T, R, G>
{
fn deref_mut(&mut self) -> &mut Self::Target {
@ -487,7 +504,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> DerefMut
}
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Drop
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Drop
for RwLockWriteGuard_<T, R, G>
{
fn drop(&mut self) {
@ -495,7 +512,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Drop
}
}
impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> fmt::Debug
impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> fmt::Debug
for RwLockWriteGuard_<T, R, G>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -505,18 +522,29 @@ impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardia
/// A guard that provides immutable data access but can be atomically
/// upgraded to `RwLockWriteGuard`.
pub struct RwLockUpgradeableGuard_<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian>
{
pub struct RwLockUpgradeableGuard_<
T: ?Sized,
R: Deref<Target = RwLock<T, G>> + Clone,
G: SpinGuardian,
> {
guard: G::Guard,
inner: R,
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> AsAtomicModeGuard
for RwLockUpgradeableGuard_<T, R, G>
{
fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
self.guard.as_atomic_mode_guard()
}
}
/// A upgradable guard that provides read access to the data protected by a [`RwLock`].
pub type RwLockUpgradeableGuard<'a, T, G> = RwLockUpgradeableGuard_<T, &'a RwLock<T, G>, G>;
/// A upgradable guard that provides read access to the data protected by a `Arc<RwLock>`.
pub type ArcRwLockUpgradeableGuard<T, G> = RwLockUpgradeableGuard_<T, Arc<RwLock<T, G>>, G>;
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian>
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian>
RwLockUpgradeableGuard_<T, R, G>
{
/// Upgrades this upread guard to a write guard atomically.
@ -554,7 +582,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian>
}
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Deref
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Deref
for RwLockUpgradeableGuard_<T, R, G>
{
type Target = T;
@ -564,7 +592,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Deref
}
}
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Drop
impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Drop
for RwLockUpgradeableGuard_<T, R, G>
{
fn drop(&mut self) {
@ -572,7 +600,7 @@ impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> Drop
}
}
impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: Guardian> fmt::Debug
impl<T: ?Sized + fmt::Debug, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> fmt::Debug
for RwLockUpgradeableGuard_<T, R, G>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View File

@ -9,7 +9,8 @@ use core::{
sync::atomic::{AtomicBool, Ordering},
};
use super::{guard::Guardian, LocalIrqDisabled, PreemptDisabled};
use super::{guard::SpinGuardian, LocalIrqDisabled, PreemptDisabled};
use crate::task::atomic_mode::AsAtomicModeGuard;
/// A spin lock.
///
@ -67,7 +68,7 @@ impl<T: ?Sized> SpinLock<T, PreemptDisabled> {
}
}
impl<T: ?Sized, G: Guardian> SpinLock<T, G> {
impl<T: ?Sized, G: SpinGuardian> SpinLock<T, G> {
/// Acquires the spin lock.
pub fn lock(&self) -> SpinLockGuard<T, G> {
// Notice the guard must be created before acquiring the lock.
@ -152,19 +153,22 @@ pub type ArcSpinLockGuard<T, G> = SpinLockGuard_<T, Arc<SpinLock<T, G>>, G>;
/// The guard of a spin lock.
#[clippy::has_significant_drop]
#[must_use]
pub struct SpinLockGuard_<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> {
pub struct SpinLockGuard_<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> {
guard: G::Guard,
lock: R,
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> SpinLockGuard_<T, R, G> {
/// Returns a reference to the guard.
pub fn guard(&self) -> &G::Guard {
&self.guard
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> AsAtomicModeGuard
for SpinLockGuard_<T, R, G>
{
fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
self.guard.as_atomic_mode_guard()
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> Deref for SpinLockGuard_<T, R, G> {
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> Deref
for SpinLockGuard_<T, R, G>
{
type Target = T;
fn deref(&self) -> &T {
@ -172,7 +176,7 @@ impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> Deref for SpinLo
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> DerefMut
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> DerefMut
for SpinLockGuard_<T, R, G>
{
fn deref_mut(&mut self) -> &mut Self::Target {
@ -180,13 +184,15 @@ impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> DerefMut
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> Drop for SpinLockGuard_<T, R, G> {
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> Drop
for SpinLockGuard_<T, R, G>
{
fn drop(&mut self) {
self.lock.release_lock();
}
}
impl<T: ?Sized + fmt::Debug, R: Deref<Target = SpinLock<T, G>>, G: Guardian> fmt::Debug
impl<T: ?Sized + fmt::Debug, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> fmt::Debug
for SpinLockGuard_<T, R, G>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -194,11 +200,14 @@ impl<T: ?Sized + fmt::Debug, R: Deref<Target = SpinLock<T, G>>, G: Guardian> fmt
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: Guardian> !Send for SpinLockGuard_<T, R, G> {}
// SAFETY: `SpinLockGuard_` can be shared between tasks/threads in same CPU.
// As `lock()` is only called when there are no race conditions caused by interrupts.
unsafe impl<T: ?Sized + Sync, R: Deref<Target = SpinLock<T, G>> + Sync, G: Guardian> Sync
impl<T: ?Sized, R: Deref<Target = SpinLock<T, G>>, G: SpinGuardian> !Send
for SpinLockGuard_<T, R, G>
{
}
// SAFETY: `SpinLockGuard_` can be shared between tasks/threads in same CPU.
// As `lock()` is only called when there are no race conditions caused by interrupts.
unsafe impl<T: ?Sized + Sync, R: Deref<Target = SpinLock<T, G>> + Sync, G: SpinGuardian> Sync
for SpinLockGuard_<T, R, G>
{
}