Skip to content

Commit e4b7ba2

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 e4b7ba2

File tree

3 files changed

+149
-1
lines changed

3 files changed

+149
-1
lines changed

drivers/char/rust_example/src/lib.rs

Lines changed: 7 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,12 @@ impl KernelModule for RustExample {
3637
println!("Parameters:");
3738
println!(" my_bool: {}", my_bool.read());
3839
println!(" my_i32: {}", my_i32.read());
40+
41+
let rust_mutex = Mutex::new(1, "rust_mutex");
42+
println!("rust_mutex: {:?}", rust_mutex);
43+
let guard = rust_mutex.lock();
44+
println!("data: {:?}", guard);
45+
drop(guard);
3946
Ok(RustExample {
4047
message: "on the heap!".to_owned(),
4148
})

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

0 commit comments

Comments
 (0)