7
7
//! See <https://www.kernel.org/doc/Documentation/locking/spinlocks.txt>.
8
8
9
9
use super :: { CreatableLock , GuardMut , Lock } ;
10
- use crate :: { bindings, str:: CStr , Opaque } ;
10
+ use crate :: { bindings, c_types , str:: CStr , Opaque } ;
11
11
use core:: { cell:: UnsafeCell , marker:: PhantomPinned , pin:: Pin } ;
12
12
13
13
/// Safely initialises a [`SpinLock`] with the given name, generating a new lock class.
@@ -26,9 +26,51 @@ macro_rules! spinlock_init {
26
26
/// used. The [`spinlock_init`] macro is provided to automatically assign a new lock class to a
27
27
/// spinlock instance.
28
28
///
29
- /// [`SpinLock`] does not manage the interrupt state, so it can be used in only two cases: (a) when
30
- /// the caller knows that interrupts are disabled, or (b) when callers never use it in interrupt
31
- /// handlers (in which case it is ok for interrupts to be enabled).
29
+ /// There are two ways to acquire the lock:
30
+ /// - [`SpinLock::lock`], which doesn't manage interrupt state, so it should be used in only two
31
+ /// cases: (a) when the caller knows that interrupts are disabled, or (b) when callers never use
32
+ /// it in atomic context (e.g., interrupt handlers), in which case it is ok for interrupts to be
33
+ /// enabled.
34
+ /// - [`SpinLock::lock_irqdisable`], which disables interrupts if they are enabled before
35
+ /// acquiring the lock. When the lock is released, the interrupt state is automatically returned
36
+ /// to its value before [`SpinLock::lock_irqdisable`] was called.
37
+ ///
38
+ /// # Examples
39
+ ///
40
+ /// ```
41
+ /// # use kernel::prelude::*;
42
+ /// # use kernel::sync::SpinLock;
43
+ /// # use core::pin::Pin;
44
+ ///
45
+ /// struct Example {
46
+ /// a: u32,
47
+ /// b: u32,
48
+ /// }
49
+ ///
50
+ /// // Function that acquires spinlock without changing interrupt state.
51
+ /// fn lock_example(value: &SpinLock<Example>) {
52
+ /// let mut guard = value.lock();
53
+ /// guard.a = 10;
54
+ /// guard.b = 20;
55
+ /// }
56
+ ///
57
+ /// // Function that acquires spinlock and disables interrupts while holding it.
58
+ /// fn lock_irqdisable_example(value: &SpinLock<Example>) {
59
+ /// let mut guard = value.lock_irqdisable();
60
+ /// guard.a = 30;
61
+ /// guard.b = 40;
62
+ /// }
63
+ ///
64
+ /// // Initialises a spinlock and calls the example functions.
65
+ /// pub fn spinlock_example() {
66
+ /// // SAFETY: `spinlock_init` is called below.
67
+ /// let mut value = unsafe { SpinLock::new(Example { a: 1, b: 2 }) };
68
+ /// // SAFETY: We don't move `value`.
69
+ /// kernel::spinlock_init!(unsafe { Pin::new_unchecked(&mut value) }, "value");
70
+ /// lock_example(&value);
71
+ /// lock_irqdisable_example(&value);
72
+ /// }
73
+ /// ```
32
74
///
33
75
/// [`spinlock_t`]: ../../../include/linux/spinlock.h
34
76
pub struct SpinLock < T : ?Sized > {
@@ -67,9 +109,24 @@ impl<T: ?Sized> SpinLock<T> {
67
109
/// Locks the spinlock and gives the caller access to the data protected by it. Only one thread
68
110
/// at a time is allowed to access the protected data.
69
111
pub fn lock ( & self ) -> GuardMut < ' _ , Self > {
70
- self . lock_noguard ( ) ;
112
+ let ctx = self . lock_noguard ( ) ;
71
113
// SAFETY: The spinlock was just acquired.
72
- unsafe { GuardMut :: new ( self , ( ) ) }
114
+ unsafe { GuardMut :: new ( self , ctx) }
115
+ }
116
+
117
+ /// Locks the spinlock and gives the caller access to the data protected by it. Additionally it
118
+ /// disables interrupts (if they are enabled).
119
+ ///
120
+ /// When the lock in unlocked, the interrupt state (enabled/disabled) is restored.
121
+ pub fn lock_irqdisable ( & self ) -> GuardMut < ' _ , Self > {
122
+ let ctx = self . internal_lock_irqsave ( ) ;
123
+ // SAFETY: The spinlock was just acquired.
124
+ unsafe { GuardMut :: new ( self , Some ( ctx) ) }
125
+ }
126
+
127
+ fn internal_lock_irqsave ( & self ) -> c_types:: c_ulong {
128
+ // SAFETY: `spin_lock` points to valid memory.
129
+ unsafe { bindings:: spin_lock_irqsave ( self . spin_lock . get ( ) ) }
73
130
}
74
131
}
75
132
@@ -91,17 +148,30 @@ impl<T> CreatableLock for SpinLock<T> {
91
148
// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
92
149
unsafe impl < T : ?Sized > Lock for SpinLock < T > {
93
150
type Inner = T ;
94
- type GuardContext = ( ) ;
151
+ type GuardContext = Option < c_types :: c_ulong > ;
95
152
96
- fn lock_noguard ( & self ) {
153
+ fn lock_noguard ( & self ) -> Option < c_types :: c_ulong > {
97
154
// SAFETY: `spin_lock` points to valid memory.
98
155
unsafe { bindings:: spin_lock ( self . spin_lock . get ( ) ) } ;
156
+ None
99
157
}
100
158
101
- unsafe fn unlock ( & self , _: & mut ( ) ) {
102
- // SAFETY: The safety requirements of the function ensure that the spinlock is owned by the
103
- // caller.
104
- unsafe { bindings:: spin_unlock ( self . spin_lock . get ( ) ) } ;
159
+ unsafe fn unlock ( & self , ctx : & mut Option < c_types:: c_ulong > ) {
160
+ match ctx {
161
+ // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
162
+ // the caller.
163
+ Some ( v) => unsafe { bindings:: spin_unlock_irqrestore ( self . spin_lock . get ( ) , * v) } ,
164
+ // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
165
+ // the caller.
166
+ None => unsafe { bindings:: spin_unlock ( self . spin_lock . get ( ) ) } ,
167
+ }
168
+ }
169
+
170
+ fn relock ( & self , ctx : & mut Self :: GuardContext ) {
171
+ match ctx {
172
+ Some ( v) => * v = self . internal_lock_irqsave ( ) ,
173
+ None => * ctx = self . lock_noguard ( ) ,
174
+ }
105
175
}
106
176
107
177
fn locked_data ( & self ) -> & UnsafeCell < T > {
0 commit comments