Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/io/poll.rs
49156 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
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]
67
pub 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>
73
where
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
/// ```
149
pub 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>
155
where
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
}
174
175