rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] rust: Add read_poll_timeout
@ 2025-08-21  0:20 FUJITA Tomonori
  2025-08-21  0:20 ` [PATCH v3 1/2] rust: Add cpu_relax() helper FUJITA Tomonori
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: FUJITA Tomonori @ 2025-08-21  0:20 UTC (permalink / raw)
  To: a.hindborg, alex.gaynor, ojeda
  Cc: aliceryhl, anna-maria, bjorn3_gh, boqun.feng, dakr, frederic,
	gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd,
	tglx, tmgross, acourbot, daniel.almeida

Add a helper function to poll periodically until a condition is met or
a timeout is reached.

This patch was previously reviewed as part of another patchset [1] but
was removed to expedite merging into the mainline. Now that all the
features it depends on have been merged into the mainline, it is being
reposted as a new independent patchset.

I put this function kernel/io/poll.rs. This function is not
necessarily related to I/O though. I don't think this function
perfectly matches the existing abstraction. Suggestions for a more
appropriate place are welcome.

v3
- update the comments
v2: https://lore.kernel.org/lkml/20250817044724.3528968-1-fujita.tomonori@gmail.com/
- make cpu_relax() inline
- remove the example code to call might_sleep with a lock hold
- move kernel/time/poll.rs to kernel/io/poll.rs
- remove the Option for timeout argument
- avoid the extra variable, sleep.
- update the comment and commit message
- writing closures directly inline in the example code
v1: https://lore.kernel.org/lkml/20250811041039.3231548-1-fujita.tomonori@gmail.com/
The changes since the last posting [2] are
- removed might_sleep() change since it was already merged separately.
- split out cpu_relax() in a separate patch
- make the example code compilable
- update the code to use Clocksource (MONOTONIC)
- call might_sleep() always (even when the function doesn't sleep)
- cosmetic changes to the doc

[1] https://lore.kernel.org/lkml/20250207132623.168854-1-fujita.tomonori@gmail.com/
[2] https://lore.kernel.org/lkml/20250220070611.214262-8-fujita.tomonori@gmail.com/


FUJITA Tomonori (2):
  rust: Add cpu_relax() helper
  rust: Add read_poll_timeout function

 rust/helpers/helpers.c   |   1 +
 rust/helpers/processor.c |   8 +++
 rust/kernel/io.rs        |   1 +
 rust/kernel/io/poll.rs   | 104 +++++++++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs       |   1 +
 rust/kernel/processor.rs |  14 ++++++
 6 files changed, 129 insertions(+)
 create mode 100644 rust/helpers/processor.c
 create mode 100644 rust/kernel/io/poll.rs
 create mode 100644 rust/kernel/processor.rs


base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 1/2] rust: Add cpu_relax() helper
  2025-08-21  0:20 [PATCH v3 0/2] rust: Add read_poll_timeout FUJITA Tomonori
@ 2025-08-21  0:20 ` FUJITA Tomonori
  2025-08-21 14:41   ` Miguel Ojeda
  2025-08-21  0:20 ` [PATCH v3 2/2] rust: Add read_poll_timeout function FUJITA Tomonori
  2025-08-21 19:39 ` [PATCH v3 0/2] rust: Add read_poll_timeout Danilo Krummrich
  2 siblings, 1 reply; 5+ messages in thread
From: FUJITA Tomonori @ 2025-08-21  0:20 UTC (permalink / raw)
  To: a.hindborg, alex.gaynor, ojeda
  Cc: aliceryhl, anna-maria, bjorn3_gh, boqun.feng, dakr, frederic,
	gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd,
	tglx, tmgross, acourbot, daniel.almeida

Add cpu_relax() helper in preparation for supporting
read_poll_timeout().

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/helpers/helpers.c   |  1 +
 rust/helpers/processor.c |  8 ++++++++
 rust/kernel/lib.rs       |  1 +
 rust/kernel/processor.rs | 14 ++++++++++++++
 4 files changed, 24 insertions(+)
 create mode 100644 rust/helpers/processor.c
 create mode 100644 rust/kernel/processor.rs

diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 7cf7fe95e41d..04598665e7c8 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -34,6 +34,7 @@
 #include "pid_namespace.c"
 #include "platform.c"
 #include "poll.c"
+#include "processor.c"
 #include "property.c"
 #include "rbtree.c"
 #include "rcu.c"
diff --git a/rust/helpers/processor.c b/rust/helpers/processor.c
new file mode 100644
index 000000000000..d41355e14d6e
--- /dev/null
+++ b/rust/helpers/processor.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/processor.h>
+
+void rust_helper_cpu_relax(void)
+{
+	cpu_relax();
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index ed53169e795c..c098c47c1817 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -110,6 +110,7 @@
 pub mod platform;
 pub mod prelude;
 pub mod print;
+pub mod processor;
 pub mod rbtree;
 pub mod regulator;
 pub mod revocable;
diff --git a/rust/kernel/processor.rs b/rust/kernel/processor.rs
new file mode 100644
index 000000000000..85b49b3614dd
--- /dev/null
+++ b/rust/kernel/processor.rs
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Processor related primitives.
+//!
+//! C header: [`include/linux/processor.h`](srctree/include/linux/processor.h)
+
+/// Lower CPU power consumption or yield to a hyperthreaded twin processor.
+///
+/// It also happens to serve as a compiler barrier.
+#[inline]
+pub fn cpu_relax() {
+    // SAFETY: Always safe to call.
+    unsafe { bindings::cpu_relax() }
+}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v3 2/2] rust: Add read_poll_timeout function
  2025-08-21  0:20 [PATCH v3 0/2] rust: Add read_poll_timeout FUJITA Tomonori
  2025-08-21  0:20 ` [PATCH v3 1/2] rust: Add cpu_relax() helper FUJITA Tomonori
@ 2025-08-21  0:20 ` FUJITA Tomonori
  2025-08-21 19:39 ` [PATCH v3 0/2] rust: Add read_poll_timeout Danilo Krummrich
  2 siblings, 0 replies; 5+ messages in thread
From: FUJITA Tomonori @ 2025-08-21  0:20 UTC (permalink / raw)
  To: a.hindborg, alex.gaynor, ojeda
  Cc: aliceryhl, anna-maria, bjorn3_gh, boqun.feng, dakr, frederic,
	gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd,
	tglx, tmgross, acourbot, daniel.almeida, Fiona Behrens

Add read_poll_timeout function which polls periodically until a
condition is met, an error occurs, or the timeout is reached.

The C's read_poll_timeout (include/linux/iopoll.h) is a complicated
macro and a simple wrapper for Rust doesn't work. So this implements
the same functionality in Rust.

The C version uses usleep_range() while the Rust version uses
fsleep(), which uses the best sleep method so it works with spans that
usleep_range() doesn't work nicely with.

The sleep_before_read argument isn't supported since there is no user
for now. It's rarely used in the C version.

Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Tested-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/kernel/io.rs      |   1 +
 rust/kernel/io/poll.rs | 104 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 rust/kernel/io/poll.rs

diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 03b467722b86..ee182b0b5452 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -8,6 +8,7 @@
 use crate::{bindings, build_assert, ffi::c_void};
 
 pub mod mem;
+pub mod poll;
 pub mod resource;
 
 pub use resource::Resource;
diff --git a/rust/kernel/io/poll.rs b/rust/kernel/io/poll.rs
new file mode 100644
index 000000000000..7af1934e397a
--- /dev/null
+++ b/rust/kernel/io/poll.rs
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IO polling.
+//!
+//! C header: [`include/linux/iopoll.h`](srctree/include/linux/iopoll.h).
+
+use crate::{
+    error::{code::*, Result},
+    processor::cpu_relax,
+    task::might_sleep,
+    time::{delay::fsleep, Delta, Instant, Monotonic},
+};
+
+/// Polls periodically until a condition is met, an error occurs,
+/// or the timeout is reached.
+///
+/// The function repeatedly executes the given operation `op` closure and
+/// checks its result using the condition closure `cond`.
+///
+/// If `cond` returns `true`, the function returns successfully with
+/// the result of `op`. Otherwise, it waits for a duration specified
+/// by `sleep_delta` before executing `op` again.
+///
+/// This process continues until either `op` returns an error, `cond`
+/// returns `true`, or the timeout specified by `timeout_delta` is
+/// reached.
+///
+/// This function can only be used in a nonatomic context.
+///
+/// # Errors
+///
+/// If `op` returns an error, then that error is returned directly.
+///
+/// If the timeout specified by `timeout_delta` is reached, then
+/// `Err(ETIMEDOUT)` is returned.
+///
+/// # Examples
+///
+/// ```no_run
+/// use kernel::io::{Io, poll::read_poll_timeout};
+/// use kernel::time::Delta;
+///
+/// const HW_READY: u16 = 0x01;
+///
+/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result<()> {
+///     match read_poll_timeout(
+///         // The `op` closure reads the value of a specific status register.
+///         || io.try_read16(0x1000),
+///         // The `cond` closure takes a reference to the value returned by `op`
+///         // and checks whether the hardware is ready.
+///         |val: &u16| *val == HW_READY,
+///         Delta::from_millis(50),
+///         Delta::from_secs(3),
+///     ) {
+///         Ok(_) => {
+///             // The hardware is ready. The returned value of the `op` closure
+///             // isn't used.
+///             Ok(())
+///         }
+///         Err(e) => Err(e),
+///     }
+/// }
+/// ```
+#[track_caller]
+pub fn read_poll_timeout<Op, Cond, T>(
+    mut op: Op,
+    mut cond: Cond,
+    sleep_delta: Delta,
+    timeout_delta: Delta,
+) -> Result<T>
+where
+    Op: FnMut() -> Result<T>,
+    Cond: FnMut(&T) -> bool,
+{
+    let start: Instant<Monotonic> = Instant::now();
+
+    // Unlike the C version, we always call `might_sleep()` unconditionally,
+    // as conditional calls are error-prone. We clearly separate
+    // `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid
+    // tools like klint.
+    might_sleep();
+
+    loop {
+        let val = op()?;
+        if cond(&val) {
+            // Unlike the C version, we immediately return.
+            // We know the condition is met so we don't need to check again.
+            return Ok(val);
+        }
+
+        if start.elapsed() > timeout_delta {
+            // Unlike the C version, we immediately return.
+            // We have just called `op()` so we don't need to call it again.
+            return Err(ETIMEDOUT);
+        }
+
+        if !sleep_delta.is_zero() {
+            fsleep(sleep_delta);
+        }
+
+        // fsleep() could be busy-wait loop so we always call cpu_relax().
+        cpu_relax();
+    }
+}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/2] rust: Add cpu_relax() helper
  2025-08-21  0:20 ` [PATCH v3 1/2] rust: Add cpu_relax() helper FUJITA Tomonori
@ 2025-08-21 14:41   ` Miguel Ojeda
  0 siblings, 0 replies; 5+ messages in thread
From: Miguel Ojeda @ 2025-08-21 14:41 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: a.hindborg, alex.gaynor, ojeda, aliceryhl, anna-maria, bjorn3_gh,
	boqun.feng, dakr, frederic, gary, jstultz, linux-kernel, lossin,
	lyude, rust-for-linux, sboyd, tglx, tmgross, acourbot,
	daniel.almeida

On Thu, Aug 21, 2025 at 2:22 AM FUJITA Tomonori
<fujita.tomonori@gmail.com> wrote:
>
> Add cpu_relax() helper in preparation for supporting
> read_poll_timeout().
>
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>

Acked-by: Miguel Ojeda <ojeda@kernel.org>

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 0/2] rust: Add read_poll_timeout
  2025-08-21  0:20 [PATCH v3 0/2] rust: Add read_poll_timeout FUJITA Tomonori
  2025-08-21  0:20 ` [PATCH v3 1/2] rust: Add cpu_relax() helper FUJITA Tomonori
  2025-08-21  0:20 ` [PATCH v3 2/2] rust: Add read_poll_timeout function FUJITA Tomonori
@ 2025-08-21 19:39 ` Danilo Krummrich
  2 siblings, 0 replies; 5+ messages in thread
From: Danilo Krummrich @ 2025-08-21 19:39 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: a.hindborg, alex.gaynor, ojeda, aliceryhl, anna-maria, bjorn3_gh,
	boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude,
	rust-for-linux, sboyd, tglx, tmgross, acourbot, daniel.almeida

On 8/21/25 2:20 AM, FUJITA Tomonori wrote:
> FUJITA Tomonori (2):

Applied to driver-core-testing, thanks!

>    rust: Add cpu_relax() helper
>    rust: Add read_poll_timeout function

     [ Fix a minor typo and add missing backticks. - Danilo ]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-08-21 19:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-21  0:20 [PATCH v3 0/2] rust: Add read_poll_timeout FUJITA Tomonori
2025-08-21  0:20 ` [PATCH v3 1/2] rust: Add cpu_relax() helper FUJITA Tomonori
2025-08-21 14:41   ` Miguel Ojeda
2025-08-21  0:20 ` [PATCH v3 2/2] rust: Add read_poll_timeout function FUJITA Tomonori
2025-08-21 19:39 ` [PATCH v3 0/2] rust: Add read_poll_timeout Danilo Krummrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).