From 9fdcc4148498b3235b8aa709b15780bd49f32dd5 Mon Sep 17 00:00:00 2001 From: Finn Behrens Date: Sun, 29 Nov 2020 20:41:23 +0100 Subject: [PATCH] Create a Mutex type backed by the kernel mutex type Signed-off-by: Finn Behrens --- drivers/char/rust_example/src/lib.rs | 9 ++ rust/kernel/src/lib.rs | 4 +- rust/kernel/src/sync.rs | 145 +++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/src/sync.rs diff --git a/drivers/char/rust_example/src/lib.rs b/drivers/char/rust_example/src/lib.rs index fe74656d977dd5..790751c7cf0576 100644 --- a/drivers/char/rust_example/src/lib.rs +++ b/drivers/char/rust_example/src/lib.rs @@ -4,6 +4,7 @@ #![feature(global_asm)] use kernel::prelude::*; +use kernel::sync::Mutex; module! { type: RustExample, @@ -36,6 +37,14 @@ impl KernelModule for RustExample { println!("Parameters:"); println!(" my_bool: {}", my_bool.read()); println!(" my_i32: {}", my_i32.read()); + + let mutex = Mutex::new(1, "mutex"); + println!("mutex: {:?}", mutex); + unsafe { + let guard = mutex.lock(); + println!("data: {}", guard); + } + Ok(RustExample { message: "on the heap!".to_owned(), }) diff --git a/rust/kernel/src/lib.rs b/rust/kernel/src/lib.rs index 1e1d22cbd8f48d..f290e728b2f37d 100644 --- a/rust/kernel/src/lib.rs +++ b/rust/kernel/src/lib.rs @@ -3,7 +3,7 @@ //! The `kernel` crate #![no_std] -#![feature(allocator_api, alloc_error_handler)] +#![feature(allocator_api, alloc_error_handler, negative_impls)] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. @@ -24,6 +24,8 @@ pub mod prelude; pub mod printk; pub mod random; +pub mod sync; + #[cfg(CONFIG_SYSCTL)] pub mod sysctl; diff --git a/rust/kernel/src/sync.rs b/rust/kernel/src/sync.rs new file mode 100644 index 00000000000000..232b5711be41c8 --- /dev/null +++ b/rust/kernel/src/sync.rs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 + +use core::cell::UnsafeCell; +use core::fmt; +use core::ops::{Deref, DerefMut}; + +use crate::bindings; + +pub struct Mutex { + lock: bindings::mutex, + data: UnsafeCell, +} + +impl Mutex { + /// Create a new Mutex + pub fn new(data: T, _name: &'static str) -> Self { + let lock = bindings::mutex::default(); + // TODO: write mutex debug traces like .magic. + // TODO: use name in the debug version + + Self { + data: UnsafeCell::new(data), + lock, + } + } +} + +impl Mutex { + /// acquire a lock on the mutex + /// # unsafe + /// This is unsafe, as it returns a second lock if one is already help by the current process + // with CONFIG_DEBUG_LOCK_ALLOW mutex_lock is a macro, which calls mutex_lock_nested(&mutex, 0) + #[cfg(CONFIG_DEBUG_LOCK_ALLOC)] + pub unsafe fn lock<'a>(&'a self) -> MutexGuard<'a, T> { + unsafe { + bindings::mutex_lock_nested( + &self.lock as *const bindings::mutex as *mut bindings::mutex, + 0, + ); + } + MutexGuard { inner: &self } + } + + /// acquire a lock on the mutex + /// # unsafe + /// This is unsafe, as it returns a second lock if one is already help by the current process + #[cfg(not(CONFIG_DEBUG_LOCK_ALLOC))] + pub unsafe fn lock<'a>(&'a self) -> MutexGuard<'a, T> { + unsafe { + bindings::mutex_lock(&self.lock as *const bindings::mutex as *mut bindings::mutex); + } + MutexGuard { inner: &self } + } + + /// try to acquire the lock, returns none on failure + /// # unsafe + /// This is unsafe, as it returns a second lock if one is already help by the current process + pub unsafe fn trylock<'a>(&'a self) -> Option> { + let ret = unsafe { + bindings::mutex_trylock(&self.lock as *const bindings::mutex as *mut bindings::mutex) + }; + if ret == 1 { + Some(MutexGuard { inner: &self }) + } else { + None + } + } + + /// test if the mutex is locked + pub fn is_locked(&self) -> bool { + unsafe { + bindings::mutex_is_locked(&self.lock as *const bindings::mutex as *mut bindings::mutex) + } + } + + fn unlock(&self) { + unsafe { + bindings::mutex_unlock(&self.lock as *const bindings::mutex as *mut bindings::mutex); + } + } +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +impl fmt::Debug for Mutex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // kindly borrowed from std::sync::Mutex + match unsafe { self.trylock() } { + Some(guard) => f.debug_struct("Mutex").field("data", &guard).finish(), + None => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } + } + + f.debug_struct("Mutex") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +#[must_use] +pub struct MutexGuard<'a, T: ?Sized> { + inner: &'a Mutex, +} + +impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> {} +unsafe impl<'a, T: ?Sized> Sync for MutexGuard<'a, T> {} + +impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.inner.data.get() } + } +} + +impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.inner.data.get() } + } +} + +impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.deref(), f) + } +} + +impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.deref(), f) + } +} + +impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { + fn drop(&mut self) { + self.inner.unlock(); + } +}