Skip to content

Commit 41cc21a

Browse files
authored
Merge pull request #679 from wedsonaf/lock-info
rust: define `LockInfo` trait that lock "type states" must implement
2 parents 2f9a757 + 6cef8bd commit 41cc21a

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)