Skip to content

Commit 9fdcc41

Browse files
committed
Create a Mutex<T> type backed by the kernel mutex type
Signed-off-by: Finn Behrens <[email protected]>
1 parent 514443c commit 9fdcc41

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

drivers/char/rust_example/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![feature(global_asm)]
55

66
use kernel::prelude::*;
7+
use kernel::sync::Mutex;
78

89
module! {
910
type: RustExample,
@@ -36,6 +37,14 @@ impl KernelModule for RustExample {
3637
println!("Parameters:");
3738
println!(" my_bool: {}", my_bool.read());
3839
println!(" my_i32: {}", my_i32.read());
40+
41+
let mutex = Mutex::new(1, "mutex");
42+
println!("mutex: {:?}", mutex);
43+
unsafe {
44+
let guard = mutex.lock();
45+
println!("data: {}", guard);
46+
}
47+
3948
Ok(RustExample {
4049
message: "on the heap!".to_owned(),
4150
})

rust/kernel/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! The `kernel` crate
44
55
#![no_std]
6-
#![feature(allocator_api, alloc_error_handler)]
6+
#![feature(allocator_api, alloc_error_handler, negative_impls)]
77

88
// Ensure conditional compilation based on the kernel configuration works;
99
// otherwise we may silently break things like initcall handling.
@@ -24,6 +24,8 @@ pub mod prelude;
2424
pub mod printk;
2525
pub mod random;
2626

27+
pub mod sync;
28+
2729
#[cfg(CONFIG_SYSCTL)]
2830
pub mod sysctl;
2931

rust/kernel/src/sync.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use core::cell::UnsafeCell;
4+
use core::fmt;
5+
use core::ops::{Deref, DerefMut};
6+
7+
use crate::bindings;
8+
9+
pub struct Mutex<T: ?Sized> {
10+
lock: bindings::mutex,
11+
data: UnsafeCell<T>,
12+
}
13+
14+
impl<T> Mutex<T> {
15+
/// Create a new Mutex
16+
pub fn new(data: T, _name: &'static str) -> Self {
17+
let lock = bindings::mutex::default();
18+
// TODO: write mutex debug traces like .magic.
19+
// TODO: use name in the debug version
20+
21+
Self {
22+
data: UnsafeCell::new(data),
23+
lock,
24+
}
25+
}
26+
}
27+
28+
impl<T: ?Sized> Mutex<T> {
29+
/// acquire a lock on the mutex
30+
/// # unsafe
31+
/// This is unsafe, as it returns a second lock if one is already help by the current process
32+
// with CONFIG_DEBUG_LOCK_ALLOW mutex_lock is a macro, which calls mutex_lock_nested(&mutex, 0)
33+
#[cfg(CONFIG_DEBUG_LOCK_ALLOC)]
34+
pub unsafe fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
35+
unsafe {
36+
bindings::mutex_lock_nested(
37+
&self.lock as *const bindings::mutex as *mut bindings::mutex,
38+
0,
39+
);
40+
}
41+
MutexGuard { inner: &self }
42+
}
43+
44+
/// acquire a lock on the mutex
45+
/// # unsafe
46+
/// This is unsafe, as it returns a second lock if one is already help by the current process
47+
#[cfg(not(CONFIG_DEBUG_LOCK_ALLOC))]
48+
pub unsafe fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
49+
unsafe {
50+
bindings::mutex_lock(&self.lock as *const bindings::mutex as *mut bindings::mutex);
51+
}
52+
MutexGuard { inner: &self }
53+
}
54+
55+
/// try to acquire the lock, returns none on failure
56+
/// # unsafe
57+
/// This is unsafe, as it returns a second lock if one is already help by the current process
58+
pub unsafe fn trylock<'a>(&'a self) -> Option<MutexGuard<'a, T>> {
59+
let ret = unsafe {
60+
bindings::mutex_trylock(&self.lock as *const bindings::mutex as *mut bindings::mutex)
61+
};
62+
if ret == 1 {
63+
Some(MutexGuard { inner: &self })
64+
} else {
65+
None
66+
}
67+
}
68+
69+
/// test if the mutex is locked
70+
pub fn is_locked(&self) -> bool {
71+
unsafe {
72+
bindings::mutex_is_locked(&self.lock as *const bindings::mutex as *mut bindings::mutex)
73+
}
74+
}
75+
76+
fn unlock(&self) {
77+
unsafe {
78+
bindings::mutex_unlock(&self.lock as *const bindings::mutex as *mut bindings::mutex);
79+
}
80+
}
81+
}
82+
83+
unsafe impl<T: ?Sized> Send for Mutex<T> {}
84+
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
85+
86+
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
87+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88+
// kindly borrowed from std::sync::Mutex
89+
match unsafe { self.trylock() } {
90+
Some(guard) => f.debug_struct("Mutex").field("data", &guard).finish(),
91+
None => {
92+
struct LockedPlaceholder;
93+
impl fmt::Debug for LockedPlaceholder {
94+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95+
f.write_str("<locked>")
96+
}
97+
}
98+
99+
f.debug_struct("Mutex")
100+
.field("data", &LockedPlaceholder)
101+
.finish()
102+
}
103+
}
104+
}
105+
}
106+
107+
#[must_use]
108+
pub struct MutexGuard<'a, T: ?Sized> {
109+
inner: &'a Mutex<T>,
110+
}
111+
112+
impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> {}
113+
unsafe impl<'a, T: ?Sized> Sync for MutexGuard<'a, T> {}
114+
115+
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
116+
type Target = T;
117+
118+
fn deref(&self) -> &Self::Target {
119+
unsafe { &*self.inner.data.get() }
120+
}
121+
}
122+
123+
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
124+
fn deref_mut(&mut self) -> &mut Self::Target {
125+
unsafe { &mut *self.inner.data.get() }
126+
}
127+
}
128+
129+
impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
130+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131+
fmt::Debug::fmt(self.deref(), f)
132+
}
133+
}
134+
135+
impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> {
136+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137+
fmt::Display::fmt(self.deref(), f)
138+
}
139+
}
140+
141+
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
142+
fn drop(&mut self) {
143+
self.inner.unlock();
144+
}
145+
}

0 commit comments

Comments
 (0)