Introduce an owned mutex that can be passed as bindings::mutex when initializing C data structures. The kernel will be locking it without user intervention so there is no data to protect and no guard type. Signed-off-by: Daniel Almeida <daniel.almeida@xxxxxxxxxxxxx> --- rust/kernel/sync.rs | 1 + rust/kernel/sync/ffi_mutex.rs | 70 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 rust/kernel/sync/ffi_mutex.rs diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index b07db83972ac..1415062be34d 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -26,6 +26,7 @@ use core::{cell::UnsafeCell, mem::MaybeUninit, pin::Pin}; mod arc; mod condvar; +pub mod ffi_mutex; mod guard; mod locked_by; mod mutex; diff --git a/rust/kernel/sync/ffi_mutex.rs b/rust/kernel/sync/ffi_mutex.rs new file mode 100644 index 000000000000..e615ec4059f6 --- /dev/null +++ b/rust/kernel/sync/ffi_mutex.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! An owned mutex that can be passed as bindings::mutex when initializing C +//! data structures. The kernel will be locking it without user intervention so +//! there is no data to protect and no guard type. + +#![allow(dead_code)] + +use crate::prelude::*; +use crate::sync::{LockClassKey, LockIniter}; +use core::marker::PhantomPinned; +use core::pin::Pin; + +use crate::Opaque; + +/// An owned mutex that can be passed as bindings::mutex when initializing C +/// data structures. The kernel will be locking it without user intervention so +/// there is no data to protect and no guard type. +pub struct FfiMutex { + mutex: Opaque<bindings::mutex>, + _pin: PhantomPinned, +} + +impl FfiMutex { + /// Constructs a new Mutex for FFI purposes. + /// + /// # Safety + /// + /// The caller must call [`FfiMutex::init_lock`] before using the raw Mutex. + pub const unsafe fn new() -> Self { + Self { + mutex: Opaque::uninit(), + _pin: PhantomPinned, + } + } + + /// Returns the inner bindings::mutex + /// + /// # Safety + /// + /// The caller must call [`FfiMutex::init_lock`] before using the raw Mutex. + pub(crate) unsafe fn raw(self: &mut Pin<&mut Self>) -> *mut bindings::mutex { + let this = self.as_mut(); + // SAFETY: mutex is pinned when Lock is. The argument to the function is not moved. + let this = unsafe { this.map_unchecked_mut(|x| &mut x.mutex) }; + // This does not move from the field. + this.get() + } +} + +impl LockIniter for FfiMutex { + fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey) { + unsafe { bindings::__mutex_init(self.mutex.get(), name.as_char_ptr(), key.get()) }; + } +} + +// SAFETY: the underlying bindings::mutex can be used from any thread. +unsafe impl Send for FfiMutex {} +// SAFETY: two threads can try locking the underlying bindings::mutex at the +// same thread without issues. +unsafe impl Sync for FfiMutex {} + +/// Safely initialises a [`FfiMutex`] with the given name, generating a new lock +/// class. +#[macro_export] +macro_rules! ffi_mutex_init { + ($mutex:expr, $name:literal) => { + $crate::init_with_lockdep!($mutex, $name); + }; +} -- 2.40.0