Skip to content

Commit d0d1dba

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 d0d1dba

File tree

3 files changed

+148
-1
lines changed

3 files changed

+148
-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: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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: debug foo
26+
27+
Self {
28+
data: UnsafeCell::new(data),
29+
lock
30+
}
31+
}
32+
}
33+
34+
impl<T: ?Sized> Mutex<T> {
35+
/// acquire a lock on the mutex
36+
#[cfg(CONFIG_DEBUG_LOCK_ALLOC)]
37+
pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
38+
unsafe {
39+
//bindings::mutex_lock(&self.lock as *const bindings::mutex as *mut bindings::mutex);
40+
bindings::mutex_lock_nested(&self.lock as *const bindings::mutex as *mut bindings::mutex, 0);
41+
}
42+
MutexGuard { inner: &self }
43+
}
44+
45+
/// acquire a lock on the mutex
46+
#[cfg(not(CONFIG_DEBUG_LOCK_ALLOC))]
47+
pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
48+
unsafe {
49+
bindings::mutex_lock(&self.lock as *const bindings::mutex as *mut bindings::mutex);
50+
}
51+
MutexGuard { inner: &self }
52+
}
53+
54+
/// try to acquire the lock, returns none on failure
55+
pub fn try_lock<'a>(&'a self) -> Option<MutexGuard<'a, T>> {
56+
let ret = unsafe { bindings::mutex_trylock(&self.lock as *const bindings::mutex as *mut bindings::mutex) };
57+
if ret == 1 {
58+
Some(MutexGuard { inner: &self })
59+
} else {
60+
None
61+
}
62+
}
63+
64+
/// test if the mutex is locked
65+
pub fn is_locked(&self) -> bool {
66+
unsafe {
67+
bindings::mutex_is_locked(&self.lock as *const bindings::mutex as *mut bindings::mutex)
68+
}
69+
}
70+
71+
fn unlock(&self) {
72+
unsafe {
73+
bindings::mutex_unlock(&self.lock as *const bindings::mutex as *mut bindings::mutex);
74+
}
75+
}
76+
}
77+
78+
unsafe impl<T: ?Sized> Send for Mutex<T> { }
79+
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
80+
81+
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
82+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83+
// kindly borrowed from std::sync::Mutex
84+
match self.try_lock() {
85+
Some(guard) => f.debug_struct("Mutex").field("data", &guard).finish(),
86+
None => {
87+
struct LockedPlaceholder;
88+
impl fmt::Debug for LockedPlaceholder {
89+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90+
f.write_str("<locked>")
91+
}
92+
}
93+
94+
f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish()
95+
},
96+
}
97+
}
98+
}
99+
100+
pub struct MutexGuard<'a, T: ?Sized> {
101+
inner: &'a Mutex<T>,
102+
}
103+
104+
105+
impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { }
106+
unsafe impl<'a, T: ?Sized> Sync for MutexGuard<'a, T> { }
107+
108+
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
109+
type Target = T;
110+
111+
fn deref(&self) -> &Self::Target {
112+
unsafe { &*self.inner.data.get() }
113+
}
114+
}
115+
116+
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
117+
fn deref_mut(&mut self) -> &mut Self::Target {
118+
unsafe { &mut *self.inner.data.get() }
119+
}
120+
}
121+
122+
impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
123+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124+
fmt::Debug::fmt(self.deref(), f)
125+
}
126+
}
127+
128+
impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> {
129+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130+
fmt::Display::fmt(self.deref(), f)
131+
}
132+
}
133+
134+
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
135+
fn drop(&mut self) {
136+
self.inner.unlock();
137+
}
138+
}

0 commit comments

Comments
 (0)