All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andreas Hindborg <a.hindborg@kernel.org>
To: Alice Ryhl <aliceryhl@google.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4] rust: add global lock support
Date: Thu, 10 Oct 2024 15:57:38 +0200	[thread overview]
Message-ID: <87r08okqlp.fsf@kernel.org> (raw)
In-Reply-To: <20240930-static-mutex-v4-1-c59555413127@google.com> (Alice Ryhl's message of "Mon, 30 Sep 2024 13:11:17 +0000")

Hi Alice,

Alice Ryhl <aliceryhl@google.com> writes:

> Add support for creating global variables that are wrapped in a mutex or
> spinlock. Optionally, the macro can generate a special LockedBy type
> that does not require a runtime check.
>
> The implementation here is intended to replace the global mutex
> workaround found in the Rust Binder RFC [1]. In both cases, the global
> lock must be initialized before first use. The macro is unsafe to use
> for the same reason.
>
> The separate initialization step is required because it is tricky to
> access the value of __ARCH_SPIN_LOCK_UNLOCKED from Rust. Doing so will
> require changes to the C side. That change will happen as a follow-up to
> this patch.

Why is this a challenge? It seems to work with locks that are not
global.

[...]

> diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global.rs
> new file mode 100644
> index 000000000000..fc02fac864f6
> --- /dev/null
> +++ b/rust/kernel/sync/lock/global.rs
> @@ -0,0 +1,260 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +// Copyright (C) 2024 Google LLC.
> +
> +//! Support for defining statics containing locks.
> +
> +/// Defines a global lock.
> +///
> +/// Supports the following options:
> +///
> +/// * `value` specifies the initial value in the global lock.
> +/// * `wrapper` specifies the name of the wrapper struct.

Could you add an example to demonstrate when using `wrapper` option
would be useful?

> +/// * `guard` specifies the name of the guard type.
> +/// * `locked_by` specifies the name of the `LockedBy` type.
> +///
> +/// # Examples
> +///
> +/// A global counter.
> +///
> +/// ```
> +/// # mod ex {
> +/// # use kernel::prelude::*;
> +/// kernel::sync::global_lock! {
> +///     // SAFETY: Initialized in module initializer before first use.
> +///     static MY_COUNTER: Mutex<u32> = unsafe { uninit };
> +///     value: 0;
> +/// }
> +///
> +/// fn increment_counter() -> u32 {
> +///     let mut guard = MY_COUNTER.lock();
> +///     *guard += 1;
> +///     *guard
> +/// }
> +///
> +/// impl kernel::Module for MyModule {
> +///     fn init(_module: &'static ThisModule) -> Result<Self> {
> +///         // SAFETY: called exactly once
> +///         unsafe { MY_COUNTER.init() };
> +///
> +///         Ok(MyModule {})
> +///     }
> +/// }
> +/// # struct MyModule {}
> +/// # }
> +/// ```
> +///
> +/// A global mutex used to protect all instances of a given struct.
> +///
> +/// ```
> +/// # mod ex {
> +/// # use kernel::prelude::*;
> +/// kernel::sync::global_lock! {
> +///     // SAFETY: Initialized in module initializer before first use.
> +///     static MY_MUTEX: Mutex<()> = unsafe { uninit };
> +///     value: ();
> +///     guard: MyGuard;
> +///     locked_by: LockedByMyMutex;
> +/// }
> +///
> +/// /// All instances of this struct are protected by `MY_MUTEX`.
> +/// struct MyStruct {
> +///     my_counter: LockedByMyMutex<u32>,
> +/// }
> +///
> +/// impl MyStruct {
> +///     /// Increment the counter in this instance.
> +///     ///
> +///     /// The caller must hold the `MY_MUTEX` mutex.
> +///     fn increment(&self, guard: &mut MyGuard) -> u32 {
> +///         let my_counter = self.my_counter.as_mut(guard);
> +///         *my_counter += 1;
> +///         *my_counter
> +///     }
> +/// }
> +///
> +/// impl kernel::Module for MyModule {
> +///     fn init(_module: &'static ThisModule) -> Result<Self> {
> +///         // SAFETY: called exactly once
> +///         unsafe { MY_MUTEX.init() };
> +///
> +///         Ok(MyModule {})
> +///     }
> +/// }
> +/// # struct MyModule {}
> +/// # }
> +/// ```
> +#[macro_export]
> +macro_rules! global_lock {
> +    {
> +        $(#[$meta:meta])* $pub:vis static $name:ident: $kind:ident<$valuety:ty> = unsafe { uninit };
> +        value: $value:expr;
> +        wrapper: $wrapper:ident;
> +        $( name: $lname:literal; )?
> +        $(
> +            guard: $guard:ident;
> +            locked_by: $locked_by:ident;
> +        )?
> +    } => {
> +        $crate::macros::paste! {
> +            type [< __static_lock_ty_ $name >] = $valuety;
> +            const [< __static_lock_init_ $name >]: [< __static_lock_ty_ $name >] = $value;
> +
> +            #[allow(unused_pub)]
> +            mod [< __static_lock_mod_ $name >] {
> +                use super::[< __static_lock_ty_ $name >] as Val;
> +                use super::[< __static_lock_init_ $name >] as INIT;
> +                type Backend = $crate::global_lock_inner!(backend $kind);
> +                type GuardTyp = $crate::global_lock_inner!(guard $kind, Val $(, $guard)?);
> +
> +                /// # Safety
> +                ///
> +                /// Must be used to initialize `super::$name`.
> +                pub(super) const unsafe fn new() -> $wrapper {
> +                    let state = $crate::types::Opaque::uninit();
> +                    $wrapper {
> +                        // SAFETY: The user of this macro promises to call `init` before calling
> +                        // `lock`.
> +                        inner: unsafe {
> +                            $crate::sync::lock::Lock::global_lock_helper_new(state, INIT)
> +                        }
> +                    }
> +                }
> +
> +                /// Wrapper type for a global lock.
> +                pub(crate) struct $wrapper {
> +                    inner: $crate::sync::lock::Lock<Val, Backend>,
> +                }
> +
> +                impl $wrapper {
> +                    /// Initialize the global lock.
> +                    ///
> +                    /// # Safety
> +                    ///
> +                    /// This method must not be called more than once.
> +                    pub(crate) unsafe fn init(&'static self) {
> +                        // SAFETY:
> +                        // * This type can only be created by `new`.
> +                        // * Caller promises to not call this method more than once.
> +                        unsafe {
> +                            $crate::sync::lock::Lock::global_lock_helper_init(
> +                                ::core::pin::Pin::static_ref(&self.inner),
> +                                $crate::optional_name!($($lname)?),
> +                                $crate::static_lock_class!(),
> +                            );
> +                        }
> +                    }
> +
> +                    /// Lock this global lock.
> +                    pub(crate) fn lock(&'static self) -> GuardTyp {
> +                        $crate::global_lock_inner!(new_guard $($guard)? {
> +                            self.inner.lock()
> +                        })
> +                    }
> +
> +                    /// Lock this global lock.

"Try to lock..." ?

Best regards,
Andreas


  parent reply	other threads:[~2024-10-10 13:57 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-30 13:11 [PATCH v4] rust: add global lock support Alice Ryhl
2024-10-10 10:39 ` Benno Lossin
2024-10-10 10:53   ` Alice Ryhl
2024-10-10 13:55     ` Boqun Feng
2024-10-10 13:58       ` Alice Ryhl
2024-10-10 14:29         ` Boqun Feng
2024-10-10 16:33           ` Boqun Feng
2024-10-10 22:21             ` Benno Lossin
2024-10-10 23:06               ` Boqun Feng
2024-10-11  7:01                 ` Benno Lossin
2024-10-11 22:43                   ` Boqun Feng
2024-10-10 22:13     ` Benno Lossin
2024-10-10 14:01   ` Andreas Hindborg
2024-10-10 22:14     ` Benno Lossin
2024-10-11 14:57       ` Andreas Hindborg
2024-10-10 13:57 ` Andreas Hindborg [this message]
2024-10-10 14:01   ` Alice Ryhl
2024-10-10 14:08     ` Andreas Hindborg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87r08okqlp.fsf@kernel.org \
    --to=a.hindborg@kernel.org \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.