File Index
Files and directories
Sign in
FILE

poll.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/io/poll.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! IO polling.
  4//!
  5//! C header: [`include/linux/iopoll.h`](srctree/include/linux/iopoll.h).
  6
  7use crate::{
  8    prelude::*,
  9    processor::cpu_relax,
 10    task::might_sleep,
 11    time::{
 12        delay::{
 13            fsleep,
 14            udelay, //
 15        },
 16        Delta,
 17        Instant,
 18        Monotonic, //
 19    },
 20};
 21
 22/// Polls periodically until a condition is met, an error occurs,
 23/// or the timeout is reached.
 24///
 25/// The function repeatedly executes the given operation `op` closure and
 26/// checks its result using the condition closure `cond`.
 27///
 28/// If `cond` returns `true`, the function returns successfully with
 29/// the result of `op`. Otherwise, it waits for a duration specified
 30/// by `sleep_delta` before executing `op` again.
 31///
 32/// This process continues until either `op` returns an error, `cond`
 33/// returns `true`, or the timeout specified by `timeout_delta` is
 34/// reached.
 35///
 36/// This function can only be used in a nonatomic context.
 37///
 38/// # Errors
 39///
 40/// If `op` returns an error, then that error is returned directly.
 41///
 42/// If the timeout specified by `timeout_delta` is reached, then
 43/// `Err(ETIMEDOUT)` is returned.
 44///
 45/// # Examples
 46///
 47/// ```no_run
 48/// use kernel::io::{Io, poll::read_poll_timeout};
 49/// use kernel::time::Delta;
 50///
 51/// const HW_READY: u16 = 0x01;
 52///
 53/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result {
 54///     read_poll_timeout(
 55///         // The `op` closure reads the value of a specific status register.
 56///         || io.try_read16(0x1000),
 57///         // The `cond` closure takes a reference to the value returned by `op`
 58///         // and checks whether the hardware is ready.
 59///         |val: &u16| *val == HW_READY,
 60///         Delta::from_millis(50),
 61///         Delta::from_secs(3),
 62///     )?;
 63///     Ok(())
 64/// }
 65/// ```
 66#[track_caller]
 67pub fn read_poll_timeout<Op, Cond, T>(
 68    mut op: Op,
 69    mut cond: Cond,
 70    sleep_delta: Delta,
 71    timeout_delta: Delta,
 72) -> Result<T>
 73where
 74    Op: FnMut() -> Result<T>,
 75    Cond: FnMut(&T) -> bool,
 76{
 77    let start: Instant<Monotonic> = Instant::now();
 78
 79    // Unlike the C version, we always call `might_sleep()` unconditionally,
 80    // as conditional calls are error-prone. We clearly separate
 81    // `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid
 82    // tools like klint.
 83    might_sleep();
 84
 85    loop {
 86        let val = op()?;
 87        if cond(&val) {
 88            // Unlike the C version, we immediately return.
 89            // We know the condition is met so we don't need to check again.
 90            return Ok(val);
 91        }
 92
 93        if start.elapsed() > timeout_delta {
 94            // Unlike the C version, we immediately return.
 95            // We have just called `op()` so we don't need to call it again.
 96            return Err(ETIMEDOUT);
 97        }
 98
 99        if !sleep_delta.is_zero() {
100            fsleep(sleep_delta);
101        }
102
103        // `fsleep()` could be a busy-wait loop so we always call `cpu_relax()`.
104        cpu_relax();
105    }
106}
107
108/// Polls periodically until a condition is met, an error occurs,
109/// or the attempt limit is reached.
110///
111/// The function repeatedly executes the given operation `op` closure and
112/// checks its result using the condition closure `cond`.
113///
114/// If `cond` returns `true`, the function returns successfully with the result of `op`.
115/// Otherwise, it performs a busy wait for a duration specified by `delay_delta`
116/// before executing `op` again.
117///
118/// This process continues until either `op` returns an error, `cond`
119/// returns `true`, or the attempt limit specified by `retry` is reached.
120///
121/// # Errors
122///
123/// If `op` returns an error, then that error is returned directly.
124///
125/// If the attempt limit specified by `retry` is reached, then
126/// `Err(ETIMEDOUT)` is returned.
127///
128/// # Examples
129///
130/// ```no_run
131/// use kernel::io::{poll::read_poll_timeout_atomic, Io};
132/// use kernel::time::Delta;
133///
134/// const HW_READY: u16 = 0x01;
135///
136/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result {
137///     read_poll_timeout_atomic(
138///         // The `op` closure reads the value of a specific status register.
139///         || io.try_read16(0x1000),
140///         // The `cond` closure takes a reference to the value returned by `op`
141///         // and checks whether the hardware is ready.
142///         |val: &u16| *val == HW_READY,
143///         Delta::from_micros(50),
144///         1000,
145///     )?;
146///     Ok(())
147/// }
148/// ```
149pub fn read_poll_timeout_atomic<Op, Cond, T>(
150    mut op: Op,
151    mut cond: Cond,
152    delay_delta: Delta,
153    retry: usize,
154) -> Result<T>
155where
156    Op: FnMut() -> Result<T>,
157    Cond: FnMut(&T) -> bool,
158{
159    for _ in 0..retry {
160        let val = op()?;
161        if cond(&val) {
162            return Ok(val);
163        }
164
165        if !delay_delta.is_zero() {
166            udelay(delay_delta);
167        }
168
169        cpu_relax();
170    }
171
172    Err(ETIMEDOUT)
173}
~/ Read-only file preview.