@@ -61,6 +61,8 @@ macro_rules! new_spinlock {
61
61
/// assert_eq!(e.c, 10);
62
62
/// assert_eq!(e.d.lock().a, 20);
63
63
/// assert_eq!(e.d.lock().b, 30);
64
+ /// assert_eq!(e.d.lock_irqsave().a, 20);
65
+ /// assert_eq!(e.d.lock_irqsave().b, 30);
64
66
/// ```
65
67
///
66
68
/// The following example shows how to use interior mutability to modify the contents of a struct
@@ -79,6 +81,12 @@ macro_rules! new_spinlock {
79
81
/// guard.a += 10;
80
82
/// guard.b += 20;
81
83
/// }
84
+ ///
85
+ /// fn example2(m: &SpinLock<Example>) {
86
+ /// let mut guard = m.lock_irqsave();
87
+ /// guard.a += 10;
88
+ /// guard.b += 20;
89
+ /// }
82
90
/// ```
83
91
///
84
92
/// [`spinlock_t`]: ../../../../include/linux/spinlock.h
@@ -90,7 +98,7 @@ pub struct SpinLockBackend;
90
98
// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
91
99
unsafe impl super :: Backend for SpinLockBackend {
92
100
type State = bindings:: spinlock_t ;
93
- type GuardState = ( ) ;
101
+ type GuardState = Option < core :: ffi :: c_ulong > ;
94
102
95
103
unsafe fn init (
96
104
ptr : * mut Self :: State ,
@@ -105,12 +113,30 @@ unsafe impl super::Backend for SpinLockBackend {
105
113
unsafe fn lock ( ptr : * mut Self :: State ) -> Self :: GuardState {
106
114
// SAFETY: The safety requirements of this function ensure that `ptr` points to valid
107
115
// memory, and that it has been initialised before.
108
- unsafe { bindings:: spin_lock ( ptr) }
116
+ unsafe { bindings:: spin_lock ( ptr) } ;
117
+ None
109
118
}
110
119
111
- unsafe fn unlock ( ptr : * mut Self :: State , _guard_state : & Self :: GuardState ) {
112
- // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
113
- // caller is the owner of the mutex.
114
- unsafe { bindings:: spin_unlock ( ptr) }
120
+ unsafe fn unlock ( ptr : * mut Self :: State , guard_state : & Self :: GuardState ) {
121
+ match guard_state {
122
+ // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that
123
+ // the caller is the owner of the mutex.
124
+ Some ( flags) => unsafe { bindings:: spin_unlock_irqrestore ( ptr, * flags) } ,
125
+ // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that
126
+ // the caller is the owner of the mutex.
127
+ None => unsafe { bindings:: spin_unlock ( ptr) } ,
128
+ }
129
+ }
130
+ }
131
+
132
+ // SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. We use the `irqsave`
133
+ // variant of the C lock acquisition functions to disable interrupts and retrieve the original
134
+ // interrupt state, and the `irqrestore` variant of the lock release functions to restore the state
135
+ // in `unlock` -- we use the guard context to determine which method was used to acquire the lock.
136
+ unsafe impl super :: IrqSaveBackend for SpinLockBackend {
137
+ unsafe fn lock_irqsave ( ptr : * mut Self :: State ) -> Self :: GuardState {
138
+ // SAFETY: The safety requirements of this function ensure that `ptr` points to valid
139
+ // memory, and that it has been initialised before.
140
+ Some ( unsafe { bindings:: spin_lock_irqsave ( ptr) } )
115
141
}
116
142
}
0 commit comments