Skip to content

Commit 6cef8bd

Browse files
committed
rust: define LockInfo trait that lock "type states" must implement
This allows the definition of additional writable type states. Without this patch, the `DerefMut` trait for guards is only implemented when the type state is `WriteLock`; this is too restrictive for types that want to implement more than one writable lock type state, for example, spin locks that may have type states that have (or have not) disabled interrupts. This is in preparation for simplifying spinlocks, which comes in a subsequent patch. Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
1 parent 2f9a757 commit 6cef8bd

File tree

9 files changed

+135
-30
lines changed

9 files changed

+135
-30
lines changed

rust/kernel/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub mod user_ptr;
9696
pub use build_error::build_error;
9797

9898
pub use crate::error::{to_result, Error, Result};
99-
pub use crate::types::{bit, bits_iter, Mode, Opaque, ScopeGuard};
99+
pub use crate::types::{bit, bits_iter, Bool, False, Mode, Opaque, ScopeGuard, True};
100100

101101
use core::marker::PhantomData;
102102

rust/kernel/sync/condvar.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! This module allows Rust code to use the kernel's [`struct wait_queue_head`] as a condition
66
//! variable.
77
8-
use super::{Guard, Lock, NeedsLockClass};
8+
use super::{Guard, Lock, LockInfo, NeedsLockClass};
99
use crate::{bindings, str::CStr, task::Task, Opaque};
1010
use core::{marker::PhantomPinned, pin::Pin};
1111

@@ -61,7 +61,7 @@ impl CondVar {
6161
///
6262
/// Returns whether there is a signal pending.
6363
#[must_use = "wait returns if a signal is pending, so the caller must check the return value"]
64-
pub fn wait<L: Lock<M>, M>(&self, guard: &mut Guard<'_, L, M>) -> bool {
64+
pub fn wait<L: Lock<I>, I: LockInfo>(&self, guard: &mut Guard<'_, L, I>) -> bool {
6565
let lock = guard.lock;
6666
let wait = Opaque::<bindings::wait_queue_entry>::uninit();
6767

rust/kernel/sync/guard.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
//! other constructs to work on generic locking primitives.
88
99
use super::NeedsLockClass;
10-
use crate::{bindings, str::CStr};
10+
use crate::{bindings, str::CStr, Bool, False, True};
1111
use core::pin::Pin;
1212

1313
/// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock
1414
/// when a guard goes out of scope. It also provides a safe and convenient way to access the data
1515
/// protected by the lock.
1616
#[must_use = "the lock unlocks immediately when the guard is unused"]
17-
pub struct Guard<'a, L: Lock<M> + ?Sized, M = WriteLock> {
17+
pub struct Guard<'a, L: Lock<I> + ?Sized, I: LockInfo = WriteLock> {
1818
pub(crate) lock: &'a L,
1919
pub(crate) context: L::GuardContext,
2020
}
@@ -23,14 +23,15 @@ pub struct Guard<'a, L: Lock<M> + ?Sized, M = WriteLock> {
2323
// conservative than the default compiler implementation; more details can be found on
2424
// https://github.com/rust-lang/rust/issues/41622 -- it refers to `MutexGuard` from the standard
2525
// library.
26-
unsafe impl<L, M> Sync for Guard<'_, L, M>
26+
unsafe impl<L, I> Sync for Guard<'_, L, I>
2727
where
28-
L: Lock<M> + ?Sized,
28+
L: Lock<I> + ?Sized,
2929
L::Inner: Sync,
30+
I: LockInfo,
3031
{
3132
}
3233

33-
impl<L: Lock<M> + ?Sized, M> core::ops::Deref for Guard<'_, L, M> {
34+
impl<L: Lock<I> + ?Sized, I: LockInfo> core::ops::Deref for Guard<'_, L, I> {
3435
type Target = L::Inner;
3536

3637
fn deref(&self) -> &Self::Target {
@@ -39,21 +40,21 @@ impl<L: Lock<M> + ?Sized, M> core::ops::Deref for Guard<'_, L, M> {
3940
}
4041
}
4142

42-
impl<L: Lock<WriteLock> + ?Sized> core::ops::DerefMut for Guard<'_, L, WriteLock> {
43+
impl<L: Lock<I> + ?Sized, I: LockInfo<Writable = True>> core::ops::DerefMut for Guard<'_, L, I> {
4344
fn deref_mut(&mut self) -> &mut Self::Target {
4445
// SAFETY: The caller owns the lock, so it is safe to deref the protected data.
4546
unsafe { &mut *self.lock.locked_data().get() }
4647
}
4748
}
4849

49-
impl<L: Lock<M> + ?Sized, M> Drop for Guard<'_, L, M> {
50+
impl<L: Lock<I> + ?Sized, I: LockInfo> Drop for Guard<'_, L, I> {
5051
fn drop(&mut self) {
5152
// SAFETY: The caller owns the lock, so it is safe to unlock it.
5253
unsafe { self.lock.unlock(&mut self.context) };
5354
}
5455
}
5556

56-
impl<'a, L: Lock<M> + ?Sized, M> Guard<'a, L, M> {
57+
impl<'a, L: Lock<I> + ?Sized, I: LockInfo> Guard<'a, L, I> {
5758
/// Constructs a new immutable lock guard.
5859
///
5960
/// # Safety
@@ -64,11 +65,23 @@ impl<'a, L: Lock<M> + ?Sized, M> Guard<'a, L, M> {
6465
}
6566
}
6667

68+
/// Specifies properties of a lock.
69+
pub trait LockInfo {
70+
/// Determines if the data protected by a lock is writable.
71+
type Writable: Bool;
72+
}
73+
6774
/// A marker for locks that only allow reading.
6875
pub struct ReadLock;
76+
impl LockInfo for ReadLock {
77+
type Writable = False;
78+
}
6979

7080
/// A marker for locks that allow reading and writing.
7181
pub struct WriteLock;
82+
impl LockInfo for WriteLock {
83+
type Writable = True;
84+
}
7285

7386
/// A generic mutual exclusion primitive.
7487
///
@@ -83,7 +96,7 @@ pub struct WriteLock;
8396
/// - Implementers of all other markers must ensure that a mutable reference to the protected data
8497
/// is not active in any thread/CPU because at least one shared refence is active between calls
8598
/// to `lock_noguard` and `unlock`.
86-
pub unsafe trait Lock<M = WriteLock> {
99+
pub unsafe trait Lock<I: LockInfo = WriteLock> {
87100
/// The type of the data protected by the lock.
88101
type Inner: ?Sized;
89102

@@ -116,13 +129,16 @@ pub unsafe trait Lock<M = WriteLock> {
116129
}
117130

118131
/// A generic mutual exclusion primitive that can be instantiated generically.
119-
pub trait CreatableLock<M = WriteLock>: Lock<M> {
132+
pub trait CreatableLock {
133+
/// The type of the argument passed to [`CreatableLock::new_lock`].
134+
type CreateArgType: ?Sized;
135+
120136
/// Constructs a new instance of the lock.
121137
///
122138
/// # Safety
123139
///
124140
/// The caller must call [`CreatableLock::init_lock`] before using the lock.
125-
unsafe fn new_lock(data: Self::Inner) -> Self;
141+
unsafe fn new_lock(data: Self::CreateArgType) -> Self;
126142

127143
/// Initialises the lock type instance so that it can be safely used.
128144
///

rust/kernel/sync/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ mod spinlock;
3535

3636
pub use arc::{Ref, RefBorrow, UniqueRef};
3737
pub use condvar::CondVar;
38-
pub use guard::{CreatableLock, Guard, Lock, ReadLock, WriteLock};
38+
pub use guard::{CreatableLock, Guard, Lock, LockInfo, ReadLock, WriteLock};
3939
pub use locked_by::LockedBy;
4040
pub use mutex::Mutex;
4141
pub use revocable_mutex::{RevocableMutex, RevocableMutexGuard};

rust/kernel/sync/mutex.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ impl<T: ?Sized> Mutex<T> {
7373
}
7474

7575
impl<T> CreatableLock for Mutex<T> {
76-
unsafe fn new_lock(data: Self::Inner) -> Self {
76+
type CreateArgType = T;
77+
78+
unsafe fn new_lock(data: Self::CreateArgType) -> Self {
7779
// SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
7880
unsafe { Self::new(data) }
7981
}

rust/kernel/sync/rwsem.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ impl<T: ?Sized> RwSemaphore<T> {
8686
}
8787

8888
impl<T> CreatableLock for RwSemaphore<T> {
89-
unsafe fn new_lock(data: Self::Inner) -> Self {
89+
type CreateArgType = T;
90+
91+
unsafe fn new_lock(data: Self::CreateArgType) -> Self {
9092
// SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
9193
unsafe { Self::new(data) }
9294
}

rust/kernel/sync/seqlock.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref, pin::Pin};
5252
/// guard.b.store(b + 1, Ordering::Relaxed);
5353
/// }
5454
/// ```
55-
pub struct SeqLock<L: CreatableLock + ?Sized> {
55+
pub struct SeqLock<L: CreatableLock + Lock + ?Sized> {
5656
_p: PhantomPinned,
5757
count: Opaque<bindings::seqcount>,
5858
write_lock: L,
@@ -61,21 +61,21 @@ pub struct SeqLock<L: CreatableLock + ?Sized> {
6161
// SAFETY: `SeqLock` can be transferred across thread boundaries iff the data it protects and the
6262
// underlying lock can.
6363
#[allow(clippy::non_send_fields_in_send_ty)]
64-
unsafe impl<L: CreatableLock + Send> Send for SeqLock<L> where L::Inner: Send {}
64+
unsafe impl<L: CreatableLock + Lock + Send> Send for SeqLock<L> where L::Inner: Send {}
6565

6666
// SAFETY: `SeqLock` allows concurrent access to the data it protects by both readers and writers,
6767
// so it requires that the data it protects be `Sync`, as well as the underlying lock.
68-
unsafe impl<L: CreatableLock + Sync> Sync for SeqLock<L> where L::Inner: Sync {}
68+
unsafe impl<L: CreatableLock + Lock + Sync> Sync for SeqLock<L> where L::Inner: Sync {}
6969

70-
impl<L: CreatableLock> SeqLock<L> {
70+
impl<L: CreatableLock + Lock> SeqLock<L> {
7171
/// Constructs a new instance of [`SeqLock`].
7272
///
7373
/// # Safety
7474
///
7575
/// The caller must call [`SeqLock::init`] before using the seqlock.
76-
pub unsafe fn new(data: L::Inner) -> Self
76+
pub unsafe fn new(data: L::CreateArgType) -> Self
7777
where
78-
L::Inner: Sized,
78+
L::CreateArgType: Sized,
7979
{
8080
Self {
8181
_p: PhantomPinned,
@@ -87,7 +87,7 @@ impl<L: CreatableLock> SeqLock<L> {
8787
}
8888
}
8989

90-
impl<L: CreatableLock + ?Sized> SeqLock<L> {
90+
impl<L: CreatableLock + Lock + ?Sized> SeqLock<L> {
9191
/// Accesses the protected data in read mode.
9292
///
9393
/// Readers and writers are allowed to run concurrently, so callers must check if they need to
@@ -129,7 +129,7 @@ impl<L: CreatableLock + ?Sized> SeqLock<L> {
129129
}
130130
}
131131

132-
impl<L: CreatableLock + ?Sized> NeedsLockClass for SeqLock<L> {
132+
impl<L: CreatableLock + Lock + ?Sized> NeedsLockClass for SeqLock<L> {
133133
unsafe fn init(
134134
mut self: Pin<&mut Self>,
135135
name: &'static CStr,
@@ -146,7 +146,7 @@ impl<L: CreatableLock + ?Sized> NeedsLockClass for SeqLock<L> {
146146
}
147147

148148
// SAFETY: The underlying lock ensures mutual exclusion.
149-
unsafe impl<L: CreatableLock + ?Sized> Lock<ReadLock> for SeqLock<L> {
149+
unsafe impl<L: CreatableLock + Lock + ?Sized> Lock<ReadLock> for SeqLock<L> {
150150
type Inner = L::Inner;
151151
type GuardContext = L::GuardContext;
152152

@@ -176,12 +176,12 @@ unsafe impl<L: CreatableLock + ?Sized> Lock<ReadLock> for SeqLock<L> {
176176
}
177177

178178
/// Allows read-side access to data protected by a sequential lock.
179-
pub struct SeqLockReadGuard<'a, L: CreatableLock + ?Sized> {
179+
pub struct SeqLockReadGuard<'a, L: CreatableLock + Lock + ?Sized> {
180180
lock: &'a SeqLock<L>,
181181
start_count: u32,
182182
}
183183

184-
impl<L: CreatableLock + ?Sized> SeqLockReadGuard<'_, L> {
184+
impl<L: CreatableLock + Lock + ?Sized> SeqLockReadGuard<'_, L> {
185185
/// Determine if the callers needs to retry reading values.
186186
///
187187
/// It returns `true` when a concurrent writer ran between the guard being created and
@@ -192,7 +192,7 @@ impl<L: CreatableLock + ?Sized> SeqLockReadGuard<'_, L> {
192192
}
193193
}
194194

195-
impl<L: CreatableLock + ?Sized> Deref for SeqLockReadGuard<'_, L> {
195+
impl<L: CreatableLock + Lock + ?Sized> Deref for SeqLockReadGuard<'_, L> {
196196
type Target = L::Inner;
197197

198198
fn deref(&self) -> &Self::Target {

rust/kernel/sync/spinlock.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ impl<T: ?Sized> SpinLock<T> {
131131
}
132132

133133
impl<T> CreatableLock for SpinLock<T> {
134-
unsafe fn new_lock(data: Self::Inner) -> Self {
134+
type CreateArgType = T;
135+
136+
unsafe fn new_lock(data: Self::CreateArgType) -> Self {
135137
// SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
136138
unsafe { Self::new(data) }
137139
}

rust/kernel/types.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,3 +484,86 @@ where
484484

485485
BitIterator { value }
486486
}
487+
488+
/// A trait for boolean types.
489+
///
490+
/// This is meant to be used in type states to allow booelan constraints in implementation blocks.
491+
/// In the example below, the implementation containing `MyType::set_value` could _not_ be
492+
/// constrained to type states containing `Writable = true` if `Writable` were a constant instead
493+
/// of a type.
494+
///
495+
/// # Safety
496+
///
497+
/// No additional implementations of [`Bool`] should be provided, as [`True`] and [`False`] are
498+
/// already provided.
499+
///
500+
/// # Examples
501+
///
502+
/// ```
503+
/// # use kernel::{Bool, False, True};
504+
/// use core::marker::PhantomData;
505+
///
506+
/// // Type state specifies whether the type is writable.
507+
/// trait MyTypeState {
508+
/// type Writable: Bool;
509+
/// }
510+
///
511+
/// // In state S1, the type is writable.
512+
/// struct S1;
513+
/// impl MyTypeState for S1 {
514+
/// type Writable = True;
515+
/// }
516+
///
517+
/// // In state S2, the type is not writable.
518+
/// struct S2;
519+
/// impl MyTypeState for S2 {
520+
/// type Writable = False;
521+
/// }
522+
///
523+
/// struct MyType<T: MyTypeState> {
524+
/// value: u32,
525+
/// _p: PhantomData<T>,
526+
/// }
527+
///
528+
/// impl<T: MyTypeState> MyType<T> {
529+
/// fn new(value: u32) -> Self {
530+
/// Self {
531+
/// value,
532+
/// _p: PhantomData,
533+
/// }
534+
/// }
535+
/// }
536+
///
537+
/// // This implementation block only applies if the type state is writable.
538+
/// impl<T> MyType<T>
539+
/// where
540+
/// T: MyTypeState<Writable = True>,
541+
/// {
542+
/// fn set_value(&mut self, v: u32) {
543+
/// self.value = v;
544+
/// }
545+
/// }
546+
///
547+
/// pub(crate) fn test() {
548+
/// let mut x = MyType::<S1>::new(10);
549+
/// let mut y = MyType::<S2>::new(20);
550+
///
551+
/// x.set_value(30);
552+
///
553+
/// // The code below fails to compile because `S2` is not writable.
554+
/// // y.set_value(40);
555+
/// }
556+
/// ```
557+
pub unsafe trait Bool {}
558+
559+
/// Represents the `true` value for types with [`Bool`] bound.
560+
pub struct True;
561+
562+
// SAFETY: This is one of the only two implementations of `Bool`.
563+
unsafe impl Bool for True {}
564+
565+
/// Represents the `false` value for types wth [`Bool`] bound.
566+
pub struct False;
567+
568+
// SAFETY: This is one of the only two implementations of `Bool`.
569+
unsafe impl Bool for False {}

0 commit comments

Comments
 (0)