ostd/sync/
guard.rs

1// SPDX-License-Identifier: MPL-2.0
2use vstd::prelude::*;
3
4use crate::{
5    task::{/* atomic_mode::AsAtomicModeGuard, */ disable_preempt, DisabledPreemptGuard},
6    trap::irq::{disable_local, DisabledLocalIrqGuard},
7};
8
9/// A guardian that denotes the guard behavior for holding a spin-based lock.
10///
11/// It at least ensures that the atomic mode is maintained while the lock is held.
12#[verus_verify]
13pub trait SpinGuardian {
14    /// The guard type for holding a spin lock or a spin-based write lock.
15    type Guard: GuardTransfer;
16    /// The guard type for holding a spin-based read lock.
17    type ReadGuard: GuardTransfer;
18
19    /// Creates a new guard.
20    fn guard() -> Self::Guard;
21    /// Creates a new read guard.
22    fn read_guard() -> Self::ReadGuard;
23}
24
25verus! {
26
27/// The Guard can be transferred atomically.
28#[verus_verify]
29pub trait GuardTransfer: Sized {
30    /// Atomically transfers the current guard to a new instance.
31    ///
32    /// This function ensures that there are no 'gaps' between the destruction of the old guard and
33    /// the creation of the new guard, thereby maintaining the atomicity of guard transitions.
34    ///
35    /// The original guard must be dropped immediately after calling this method.
36    fn transfer_to(&mut self) -> Self
37        no_unwind
38    ;
39}
40
41} // verus!
42/// A guardian that disables preemption while holding a lock.
43#[verifier::external]
44pub enum PreemptDisabled {}
45
46#[verifier::external_type_specification]
47#[verifier::external_body]
48pub struct ExPreemptDisabled(PreemptDisabled);
49
50#[verus_verify]
51impl SpinGuardian for PreemptDisabled {
52    type Guard = DisabledPreemptGuard;
53    type ReadGuard = DisabledPreemptGuard;
54
55    #[verifier::external_body]
56    fn guard() -> Self::Guard {
57        disable_preempt()
58    }
59    #[verifier::external_body]
60    fn read_guard() -> Self::Guard {
61        disable_preempt()
62    }
63}
64
65/// A guardian that disables IRQs while holding a lock.
66///
67/// This guardian would incur a certain time overhead over
68/// [`PreemptDisabled`]. So prefer avoiding using this guardian when
69/// IRQ handlers are allowed to get executed while holding the
70/// lock. For example, if a lock is never used in the interrupt
71/// context, then it is ok not to use this guardian in the process context.
72#[verifier::external]
73pub enum LocalIrqDisabled {}
74
75#[verifier::external_type_specification]
76#[verifier::external_body]
77pub struct ExLocalIrqDisabled(LocalIrqDisabled);
78
79#[verus_verify]
80impl SpinGuardian for LocalIrqDisabled {
81    type Guard = DisabledLocalIrqGuard;
82    type ReadGuard = DisabledLocalIrqGuard;
83
84    #[verifier::external_body]
85    fn guard() -> Self::Guard {
86        disable_local()
87    }
88    #[verifier::external_body]
89    fn read_guard() -> Self::Guard {
90        disable_local()
91    }
92}
93
94/// A guardian that disables IRQs while holding a write lock.
95///
96/// This guardian should only be used for a [`RwLock`]. Using it with a [`SpinLock`] will behave in
97/// the same way as using [`LocalIrqDisabled`].
98///
99/// When using this guardian with a [`RwLock`], holding the read lock will only disable preemption,
100/// but holding a write lock will disable local IRQs. The user must ensure that the IRQ handlers
101/// never take the write lock, so we can take the read lock without disabling IRQs, but we are
102/// still free of deadlock even if the IRQ handlers are triggered in the middle.
103///
104/// [`RwLock`]: super::RwLock
105/// [`SpinLock`]: super::SpinLock
106#[verifier::external]
107pub enum WriteIrqDisabled {}
108
109#[verifier::external_type_specification]
110#[verifier::external_body]
111pub struct ExWriteIrqDisabled(WriteIrqDisabled);
112
113#[verus_verify]
114impl SpinGuardian for WriteIrqDisabled {
115    type Guard = DisabledLocalIrqGuard;
116    type ReadGuard = DisabledPreemptGuard;
117
118    #[verifier::external_body]
119    fn guard() -> Self::Guard {
120        disable_local()
121    }
122    #[verifier::external_body]
123    fn read_guard() -> Self::ReadGuard {
124        disable_preempt()
125    }
126}