Re: [PATCH v1 1/2] rust: Add support for calling a function exactly once

Boqun Feng
2025-11-05T16:19:42Z

Hi Tomo,

On Wed, Nov 05, 2025 at 02:47:30PM +0900, FUJITA Tomonori wrote:
> Add the Rust equivalent of the kernel's `DO_ONCE_LITE` macro. While it
> would be possible to implement the feature entirely as a Rust macro,
> the functionality that can be implemented as regular functions has
> been extracted and implemented as the `OnceLite` struct for better
> code maintainability.
>

Thanks for the patch.

> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
> rust/kernel/lib.rs | 1 +
> rust/kernel/once_lite.rs | 71 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 72 insertions(+)
> create mode 100644 rust/kernel/once_lite.rs
>
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 3dd7bebe7888..19553eb8c188 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -110,6 +110,7 @@
> #[cfg(CONFIG_NET)]
> pub mod net;
> pub mod of;
> +pub mod once_lite;

Would it make more sense to put it the kernel::sync module?

> #[cfg(CONFIG_PM_OPP)]
> pub mod opp;
> pub mod page;
> diff --git a/rust/kernel/once_lite.rs b/rust/kernel/once_lite.rs
> new file mode 100644
> index 000000000000..44ad5dbdc67e
> --- /dev/null
> +++ b/rust/kernel/once_lite.rs
> @@ -0,0 +1,71 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Support for calling a function exactly once.
> +//!
> +//! C header: [`include/linux/once_lite.h`](srctree/include/linux/once_lite.h)
> +
> +use crate::sync::atomic::{Atomic, AtomicType, Relaxed};
> +
> +/// A lightweight `call_once` primitive.
> +///
> +/// This structure provides the Rust equivalent of the kernel's `DO_ONCE_LITE` macro.
> +/// While it would be possible to implement the feature entirely as a Rust macro,
> +/// the functionality that can be implemented as regular functions has been
> +/// extracted and implemented as the `OnceLite` struct for better code maintainability.
> +pub struct OnceLite(Atomic<State>);
> +
> +#[derive(Clone, Copy, PartialEq, Eq)]
> +#[repr(i32)]
> +enum State {
> + Incomplete = 0,
> + Complete = 1,
> +}
> +
> +// SAFETY: `State` and `i32` has the same size and alignment, and it's round-trip
> +// transmutable to `i32`.
> +unsafe impl AtomicType for State {
> + type Repr = i32;
> +}
> +
> +impl OnceLite {
> + /// Creates a new [`OnceLite`] in the incomplete state.
> + #[inline(always)]
> + #[allow(clippy::new_without_default)]
> + pub const fn new() -> Self {
> + OnceLite(Atomic::new(State::Incomplete))
> + }
> +
> + /// Calls the provided function exactly once.

I think a few more comments here won't hurt:

/// There is no other synchronization between two `call_once()`s
/// except that only one will execute `f`, in other words, callers
/// should not use a failed `call_once()` as a proof that another
/// `call_once()` has already finished and the effect is observable
/// to this thread.

Thoughts?

> + pub fn call_once<F>(&self, f: F) -> bool
> + where
> + F: FnOnce(),
> + {
> + let old = self.0.xchg(State::Complete, Relaxed);

And we probably want a // ORDERING: comment here to explain why
`Relaxed` is used here (because of the semantics mentioned above in the
comment).

Otherwise it looks good to me. Thanks!

Regards,
Boqun

> + if old == State::Complete {
> + return false;
> + }
> +
> + f();
> + true
> + }
> +}
> +
> +/// Run the given function exactly once.
> +///
> +/// This is equivalent to the kernel's `DO_ONCE_LITE` macro.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// kernel::do_once_lite!(|| {
> +/// kernel::pr_info!("This will be printed only once\n");
> +/// });
> +/// ```
> +#[macro_export]
> +macro_rules! do_once_lite {
> + ($e:expr) => {{
> + #[link_section = ".data..once"]
> + static ONCE: $crate::once_lite::OnceLite = $crate::once_lite::OnceLite::new();
> + ONCE.call_once($e)
> + }};
> +}
> --
> 2.43.0
>