Skip to content

Commit d320a36

Browse files
authored
Merge pull request #102 from Rust-for-Linux/sync
Add `sync` module with a mutex implementation.
2 parents e2b0b85 + 8a913df commit d320a36

File tree

5 files changed

+257
-1
lines changed

5 files changed

+257
-1
lines changed

drivers/char/rust_example.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use alloc::boxed::Box;
1010
use core::pin::Pin;
1111
use kernel::prelude::*;
12-
use kernel::{chrdev, cstr, file_operations::FileOperations, miscdev};
12+
use kernel::{chrdev, cstr, file_operations::FileOperations, miscdev, mutex_init, sync::Mutex};
1313

1414
module! {
1515
type: RustExample,
@@ -74,6 +74,15 @@ impl KernelModule for RustExample {
7474
println!(" my_usize: {}", my_usize.read(&lock));
7575
}
7676

77+
// Test mutexes.
78+
{
79+
// SAFETY: `init` is called below.
80+
let data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?);
81+
mutex_init!(data.as_ref(), "RustExample::init::data");
82+
*data.lock() = 10;
83+
println!("Value: {}", *data.lock());
84+
}
85+
7786
// Including this large variable on the stack will trigger
7887
// stack probing on the supported archs.
7988
// This will verify that stack probing does not lead to

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub mod prelude;
4141
pub mod printk;
4242
pub mod random;
4343
mod static_assert;
44+
pub mod sync;
4445

4546
#[cfg(CONFIG_SYSCTL)]
4647
pub mod sysctl;

rust/kernel/sync/guard.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! A generic lock guard and trait.
4+
//!
5+
//! This module contains a lock guard that can be used with any locking primitive that implements
6+
//! the ([`Lock`]) trait. It also contains the definition of the trait, which can be leveraged by
7+
//! other constructs to work on generic locking primitives.
8+
9+
/// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock
10+
/// when a guard goes out of scope. It also provides a safe and convenient way to access the data
11+
/// protected by the lock.
12+
#[must_use = "the lock unlocks immediately when the guard is unused"]
13+
pub struct Guard<'a, L: Lock + ?Sized> {
14+
pub(crate) lock: &'a L,
15+
}
16+
17+
// SAFETY: `Guard` is sync when the data protected by the lock is also sync. This is more
18+
// conservative than the default compiler implementation; more details can be found on
19+
// https://github.com/rust-lang/rust/issues/41622 -- it refers to `MutexGuard` from the standard
20+
// library.
21+
unsafe impl<L> Sync for Guard<'_, L>
22+
where
23+
L: Lock + ?Sized,
24+
L::Inner: Sync,
25+
{
26+
}
27+
28+
impl<L: Lock + ?Sized> core::ops::Deref for Guard<'_, L> {
29+
type Target = L::Inner;
30+
31+
fn deref(&self) -> &Self::Target {
32+
// SAFETY: The caller owns the lock, so it is safe to deref the protected data.
33+
unsafe { &*self.lock.locked_data().get() }
34+
}
35+
}
36+
37+
impl<L: Lock + ?Sized> core::ops::DerefMut for Guard<'_, L> {
38+
fn deref_mut(&mut self) -> &mut L::Inner {
39+
// SAFETY: The caller owns the lock, so it is safe to deref the protected data.
40+
unsafe { &mut *self.lock.locked_data().get() }
41+
}
42+
}
43+
44+
impl<L: Lock + ?Sized> Drop for Guard<'_, L> {
45+
fn drop(&mut self) {
46+
// SAFETY: The caller owns the lock, so it is safe to unlock it.
47+
unsafe { self.lock.unlock() };
48+
}
49+
}
50+
51+
impl<'a, L: Lock + ?Sized> Guard<'a, L> {
52+
/// Constructs a new lock guard.
53+
///
54+
/// # Safety
55+
///
56+
/// The caller must ensure that it owns the lock.
57+
pub(crate) unsafe fn new(lock: &'a L) -> Self {
58+
Self { lock }
59+
}
60+
}
61+
62+
/// A generic mutual exclusion primitive.
63+
///
64+
/// [`Guard`] is written such that any mutual exclusion primitive that can implement this trait can
65+
/// also benefit from having an automatic way to unlock itself.
66+
pub trait Lock {
67+
/// The type of the data protected by the lock.
68+
type Inner: ?Sized;
69+
70+
/// Acquires the lock, making the caller its owner.
71+
fn lock_noguard(&self);
72+
73+
/// Releases the lock, giving up ownership of the lock.
74+
///
75+
/// # Safety
76+
///
77+
/// It must only be called by the current owner of the lock.
78+
unsafe fn unlock(&self);
79+
80+
/// Returns the data protected by the lock.
81+
///
82+
/// # Safety
83+
///
84+
/// It must only be called by the current owner of the lock.
85+
unsafe fn locked_data(&self) -> &core::cell::UnsafeCell<Self::Inner>;
86+
}

rust/kernel/sync/mod.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Synchronisation primitives.
4+
//!
5+
//! This module contains the kernel APIs related to synchronisation that have been ported or
6+
//! wrapped for usage by Rust code in the kernel and is shared by all of them.
7+
//!
8+
//! # Example
9+
//!
10+
//!```
11+
//! fn test() {
12+
//! // SAFETY: `init` is called below.
13+
//! let data = alloc::sync::Arc::pin(unsafe{ Mutex::new(0) });
14+
//! mutex_init!(data.as_ref(), "test::data");
15+
//! *data.lock() = 10;
16+
//! kernel::println!("{}", *data.lock());
17+
//! }
18+
//! ```
19+
20+
use crate::{bindings, CStr};
21+
use core::pin::Pin;
22+
23+
mod guard;
24+
mod mutex;
25+
26+
pub use guard::{Guard, Lock};
27+
pub use mutex::Mutex;
28+
29+
/// Safely initialises an object that has an `init` function that takes a name and a lock class as
30+
/// arguments, for example, [`Mutex`].
31+
#[doc(hidden)]
32+
#[macro_export]
33+
macro_rules! init_with_lockdep {
34+
($obj:expr, $name:literal) => {{
35+
static mut CLASS: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
36+
core::mem::MaybeUninit::uninit();
37+
// SAFETY: `CLASS` is never used by Rust code directly; the kernel may change it though.
38+
#[allow(unused_unsafe)]
39+
unsafe {
40+
$crate::sync::NeedsLockClass::init($obj, $crate::cstr!($name), CLASS.as_mut_ptr())
41+
};
42+
}};
43+
}
44+
45+
/// A trait for types that need a lock class during initialisation.
46+
///
47+
/// Implementers of this trait benefit from the [`init_with_lockdep`] macro that generates a new
48+
/// class for each initialisation call site.
49+
pub trait NeedsLockClass {
50+
/// Initialises the type instance so that it can be safely used.
51+
///
52+
/// Callers are encouraged to use the [`init_with_lockdep`] macro as it automatically creates a
53+
/// new lock class on each usage.
54+
///
55+
/// # Safety
56+
///
57+
/// `key` must point to a valid memory location as it will be used by the kernel.
58+
unsafe fn init(self: Pin<&Self>, name: CStr<'static>, key: *mut bindings::lock_class_key);
59+
}

rust/kernel/sync/mutex.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! A kernel mutex.
4+
//!
5+
//! This module allows Rust code to use the kernel's [`struct mutex`].
6+
7+
use super::{Guard, Lock, NeedsLockClass};
8+
use crate::{bindings, CStr};
9+
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
10+
11+
/// Safely initialises a [`Mutex`] with the given name, generating a new lock class.
12+
#[macro_export]
13+
macro_rules! mutex_init {
14+
($mutex:expr, $name:literal) => {
15+
$crate::init_with_lockdep!($mutex, $name)
16+
};
17+
}
18+
19+
/// Exposes the kernel's [`struct mutex`]. When multiple threads attempt to lock the same mutex,
20+
/// only one at a time is allowed to progress, the others will block (sleep) until the mutex is
21+
/// unlocked, at which point another thread will be allowed to wake up and make progress.
22+
///
23+
/// A [`Mutex`] must first be initialised with a call to [`Mutex::init`] before it can be used. The
24+
/// [`mutex_init`] macro is provided to automatically assign a new lock class to a mutex instance.
25+
///
26+
/// Since it may block, [`Mutex`] needs to be used with care in atomic contexts.
27+
///
28+
/// [`struct mutex`]: ../../../include/linux/mutex.h
29+
pub struct Mutex<T: ?Sized> {
30+
/// The kernel `struct mutex` object.
31+
mutex: UnsafeCell<bindings::mutex>,
32+
33+
/// A mutex needs to be pinned because it contains a [`struct list_head`] that is
34+
/// self-referential, so it cannot be safely moved once it is initialised.
35+
_pin: PhantomPinned,
36+
37+
/// The data protected by the mutex.
38+
data: UnsafeCell<T>,
39+
}
40+
41+
// SAFETY: `Mutex` can be transferred across thread boundaries iff the data it protects can.
42+
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
43+
44+
// SAFETY: `Mutex` serialises the interior mutability it provides, so it is `Sync` as long as the
45+
// data it protects is `Send`.
46+
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
47+
48+
impl<T> Mutex<T> {
49+
/// Constructs a new mutex.
50+
///
51+
/// # Safety
52+
///
53+
/// The caller must call [`Mutex::init`] before using the mutex.
54+
pub unsafe fn new(t: T) -> Self {
55+
Self {
56+
mutex: UnsafeCell::new(bindings::mutex::default()),
57+
data: UnsafeCell::new(t),
58+
_pin: PhantomPinned,
59+
}
60+
}
61+
}
62+
63+
impl<T: ?Sized> Mutex<T> {
64+
/// Locks the mutex and gives the caller access to the data protected by it. Only one thread at
65+
/// a time is allowed to access the protected data.
66+
pub fn lock(&self) -> Guard<Self> {
67+
self.lock_noguard();
68+
// SAFETY: The mutex was just acquired.
69+
unsafe { Guard::new(self) }
70+
}
71+
}
72+
73+
impl<T: ?Sized> NeedsLockClass for Mutex<T> {
74+
unsafe fn init(self: Pin<&Self>, name: CStr<'static>, key: *mut bindings::lock_class_key) {
75+
bindings::__mutex_init(self.mutex.get(), name.as_ptr() as _, key);
76+
}
77+
}
78+
79+
impl<T: ?Sized> Lock for Mutex<T> {
80+
type Inner = T;
81+
82+
#[cfg(not(CONFIG_DEBUG_LOCK_ALLOC))]
83+
fn lock_noguard(&self) {
84+
// SAFETY: `mutex` points to valid memory.
85+
unsafe { bindings::mutex_lock(self.mutex.get()) };
86+
}
87+
88+
#[cfg(CONFIG_DEBUG_LOCK_ALLOC)]
89+
fn lock_noguard(&self) {
90+
// SAFETY: `mutex` points to valid memory.
91+
unsafe { bindings::mutex_lock_nested(self.mutex.get(), 0) };
92+
}
93+
94+
unsafe fn unlock(&self) {
95+
bindings::mutex_unlock(self.mutex.get());
96+
}
97+
98+
unsafe fn locked_data(&self) -> &UnsafeCell<T> {
99+
&self.data
100+
}
101+
}

0 commit comments

Comments
 (0)