FILE
poll.rs
File preview with syntax highlighting.
linux-6.19.14/rust/kernel/io/poll.rs
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.