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