66//!
77//! See <https://www.kernel.org/doc/Documentation/locking/spinlocks.txt>.
88
9- use super :: { CreatableLock , Guard , Lock } ;
10- use crate :: { bindings, c_types, str:: CStr , Opaque } ;
9+ use super :: { mutex :: EmptyGuardContext , CreatableLock , Guard , Lock , LockInfo , WriteLock } ;
10+ use crate :: { bindings, c_types, str:: CStr , Opaque , True } ;
1111use core:: { cell:: UnsafeCell , marker:: PhantomPinned , pin:: Pin } ;
1212
1313/// Safely initialises a [`SpinLock`] with the given name, generating a new lock class.
@@ -108,8 +108,8 @@ impl<T> SpinLock<T> {
108108impl < T : ?Sized > SpinLock < T > {
109109 /// Locks the spinlock and gives the caller access to the data protected by it. Only one thread
110110 /// at a time is allowed to access the protected data.
111- pub fn lock ( & self ) -> Guard < ' _ , Self > {
112- let ctx = self . lock_noguard ( ) ;
111+ pub fn lock ( & self ) -> Guard < ' _ , Self , WriteLock > {
112+ let ctx = < Self as Lock < WriteLock > > :: lock_noguard ( self ) ;
113113 // SAFETY: The spinlock was just acquired.
114114 unsafe { Guard :: new ( self , ctx) }
115115 }
@@ -118,15 +118,10 @@ impl<T: ?Sized> SpinLock<T> {
118118 /// disables interrupts (if they are enabled).
119119 ///
120120 /// When the lock in unlocked, the interrupt state (enabled/disabled) is restored.
121- pub fn lock_irqdisable ( & self ) -> Guard < ' _ , Self > {
122- let ctx = self . internal_lock_irqsave ( ) ;
121+ pub fn lock_irqdisable ( & self ) -> Guard < ' _ , Self , DisabledInterrupts > {
122+ let ctx = < Self as Lock < DisabledInterrupts > > :: lock_noguard ( self ) ;
123123 // SAFETY: The spinlock was just acquired.
124- unsafe { Guard :: 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 ( ) ) }
124+ unsafe { Guard :: new ( self , ctx) }
130125 }
131126}
132127
@@ -147,33 +142,48 @@ impl<T> CreatableLock for SpinLock<T> {
147142 }
148143}
149144
145+ /// A type state indicating that interrupts were disabled.
146+ pub struct DisabledInterrupts ;
147+ impl LockInfo for DisabledInterrupts {
148+ type Writable = True ;
149+ }
150+
150151// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
151152unsafe impl < T : ?Sized > Lock for SpinLock < T > {
152153 type Inner = T ;
153- type GuardContext = Option < c_types :: c_ulong > ;
154+ type GuardContext = EmptyGuardContext ;
154155
155- fn lock_noguard ( & self ) -> Option < c_types :: c_ulong > {
156+ fn lock_noguard ( & self ) -> EmptyGuardContext {
156157 // SAFETY: `spin_lock` points to valid memory.
157158 unsafe { bindings:: spin_lock ( self . spin_lock . get ( ) ) } ;
158- None
159+ EmptyGuardContext
159160 }
160161
161- unsafe fn unlock ( & self , ctx : & mut Option < c_types:: c_ulong > ) {
162- match ctx {
163- // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
164- // the caller.
165- Some ( v) => unsafe { bindings:: spin_unlock_irqrestore ( self . spin_lock . get ( ) , * v) } ,
166- // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
167- // the caller.
168- None => unsafe { bindings:: spin_unlock ( self . spin_lock . get ( ) ) } ,
169- }
162+ unsafe fn unlock ( & self , _: & mut EmptyGuardContext ) {
163+ // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
164+ // the caller.
165+ unsafe { bindings:: spin_unlock ( self . spin_lock . get ( ) ) }
170166 }
171167
172- fn relock ( & self , ctx : & mut Self :: GuardContext ) {
173- match ctx {
174- Some ( v) => * v = self . internal_lock_irqsave ( ) ,
175- None => * ctx = self . lock_noguard ( ) ,
176- }
168+ fn locked_data ( & self ) -> & UnsafeCell < T > {
169+ & self . data
170+ }
171+ }
172+
173+ // SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
174+ unsafe impl < T : ?Sized > Lock < DisabledInterrupts > for SpinLock < T > {
175+ type Inner = T ;
176+ type GuardContext = c_types:: c_ulong ;
177+
178+ fn lock_noguard ( & self ) -> c_types:: c_ulong {
179+ // SAFETY: `spin_lock` points to valid memory.
180+ unsafe { bindings:: spin_lock_irqsave ( self . spin_lock . get ( ) ) }
181+ }
182+
183+ unsafe fn unlock ( & self , ctx : & mut c_types:: c_ulong ) {
184+ // SAFETY: The safety requirements of the function ensure that the spinlock is owned by
185+ // the caller.
186+ unsafe { bindings:: spin_unlock_irqrestore ( self . spin_lock . get ( ) , * ctx) }
177187 }
178188
179189 fn locked_data ( & self ) -> & UnsafeCell < T > {
0 commit comments