Skip to content

Commit 0223500

Browse files
authored
Merge pull request #680 from wedsonaf/spinlock-simplify
rust: simplify spin lock implementation by splitting acquisition types
2 parents 41cc21a + 8447af5 commit 0223500

File tree

2 files changed

+40
-30
lines changed

2 files changed

+40
-30
lines changed

rust/kernel/sync/condvar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl CondVar {
8383
// SAFETY: No arguments, switches to another thread.
8484
unsafe { bindings::schedule() };
8585

86-
lock.relock(&mut guard.context);
86+
guard.context = lock.lock_noguard();
8787

8888
// SAFETY: Both `wait` and `wait_list` point to valid memory.
8989
unsafe { bindings::finish_wait(self.wait_list.get(), wait.get()) };

rust/kernel/sync/spinlock.rs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
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};
1111
use 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> {
108108
impl<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.
151152
unsafe 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

Comments
 (0)