Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/io/poll.rs
29266 views
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
7
use crate::{
8
error::{code::*, Result},
9
processor::cpu_relax,
10
task::might_sleep,
11
time::{delay::fsleep, Delta, Instant, Monotonic},
12
};
13
14
/// Polls periodically until a condition is met, an error occurs,
15
/// or the timeout is reached.
16
///
17
/// The function repeatedly executes the given operation `op` closure and
18
/// checks its result using the condition closure `cond`.
19
///
20
/// If `cond` returns `true`, the function returns successfully with
21
/// the result of `op`. Otherwise, it waits for a duration specified
22
/// by `sleep_delta` before executing `op` again.
23
///
24
/// This process continues until either `op` returns an error, `cond`
25
/// returns `true`, or the timeout specified by `timeout_delta` is
26
/// reached.
27
///
28
/// This function can only be used in a nonatomic context.
29
///
30
/// # Errors
31
///
32
/// If `op` returns an error, then that error is returned directly.
33
///
34
/// If the timeout specified by `timeout_delta` is reached, then
35
/// `Err(ETIMEDOUT)` is returned.
36
///
37
/// # Examples
38
///
39
/// ```no_run
40
/// use kernel::io::{Io, poll::read_poll_timeout};
41
/// use kernel::time::Delta;
42
///
43
/// const HW_READY: u16 = 0x01;
44
///
45
/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result<()> {
46
/// match read_poll_timeout(
47
/// // The `op` closure reads the value of a specific status register.
48
/// || io.try_read16(0x1000),
49
/// // The `cond` closure takes a reference to the value returned by `op`
50
/// // and checks whether the hardware is ready.
51
/// |val: &u16| *val == HW_READY,
52
/// Delta::from_millis(50),
53
/// Delta::from_secs(3),
54
/// ) {
55
/// Ok(_) => {
56
/// // The hardware is ready. The returned value of the `op` closure
57
/// // isn't used.
58
/// Ok(())
59
/// }
60
/// Err(e) => Err(e),
61
/// }
62
/// }
63
/// ```
64
#[track_caller]
65
pub fn read_poll_timeout<Op, Cond, T>(
66
mut op: Op,
67
mut cond: Cond,
68
sleep_delta: Delta,
69
timeout_delta: Delta,
70
) -> Result<T>
71
where
72
Op: FnMut() -> Result<T>,
73
Cond: FnMut(&T) -> bool,
74
{
75
let start: Instant<Monotonic> = Instant::now();
76
77
// Unlike the C version, we always call `might_sleep()` unconditionally,
78
// as conditional calls are error-prone. We clearly separate
79
// `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid
80
// tools like klint.
81
might_sleep();
82
83
loop {
84
let val = op()?;
85
if cond(&val) {
86
// Unlike the C version, we immediately return.
87
// We know the condition is met so we don't need to check again.
88
return Ok(val);
89
}
90
91
if start.elapsed() > timeout_delta {
92
// Unlike the C version, we immediately return.
93
// We have just called `op()` so we don't need to call it again.
94
return Err(ETIMEDOUT);
95
}
96
97
if !sleep_delta.is_zero() {
98
fsleep(sleep_delta);
99
}
100
101
// `fsleep()` could be a busy-wait loop so we always call `cpu_relax()`.
102
cpu_relax();
103
}
104
}
105
106