1
1
//! Wait for events to trigger on specific file descriptors
2
+ use std:: convert:: TryFrom ;
2
3
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
4
+ use std:: time:: Duration ;
3
5
4
6
use crate :: errno:: Errno ;
5
7
use crate :: Result ;
6
-
7
8
/// This is a wrapper around `libc::pollfd`.
8
9
///
9
10
/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
@@ -132,6 +133,192 @@ libc_bitflags! {
132
133
}
133
134
}
134
135
136
+ /// Timeout argument for [`poll`].
137
+ #[ derive( Debug , Clone , Copy , Eq , PartialEq , Ord , PartialOrd ) ]
138
+ pub struct PollTimeout ( i32 ) ;
139
+
140
+ impl PollTimeout {
141
+ /// Blocks indefinitely.
142
+ pub const NONE : Self = Self ( -1 ) ;
143
+ /// Returns immediately.
144
+ pub const ZERO : Self = Self ( 0 ) ;
145
+ /// Blocks for at most [`std::i32::MAX`] milliseconds.
146
+ pub const MAX : Self = Self ( i32:: MAX ) ;
147
+ /// Returns if `self` equals [`PollTimeout::NONE`].
148
+ pub fn is_none ( & self ) -> bool {
149
+ // > Specifying a negative value in timeout means an infinite timeout.
150
+ * self <= Self :: NONE
151
+ }
152
+ /// Returns if `self` does not equal [`PollTimeout::NONE`].
153
+ pub fn is_some ( & self ) -> bool {
154
+ !self . is_none ( )
155
+ }
156
+ /// Returns the timeout in milliseconds if there is some, otherwise returns `None`.
157
+ pub fn timeout ( & self ) -> Option < i32 > {
158
+ self . is_some ( ) . then_some ( self . 0 )
159
+ }
160
+ }
161
+
162
+ impl TryFrom < Duration > for PollTimeout {
163
+ type Error = <i32 as TryFrom < u128 > >:: Error ;
164
+ fn try_from ( x : Duration ) -> std:: result:: Result < Self , Self :: Error > {
165
+ Ok ( Self ( i32:: try_from ( x. as_millis ( ) ) ?) )
166
+ }
167
+ }
168
+ impl TryFrom < u128 > for PollTimeout {
169
+ type Error = <i32 as TryFrom < u128 > >:: Error ;
170
+ fn try_from ( x : u128 ) -> std:: result:: Result < Self , Self :: Error > {
171
+ Ok ( Self ( i32:: try_from ( x) ?) )
172
+ }
173
+ }
174
+ impl TryFrom < u64 > for PollTimeout {
175
+ type Error = <i32 as TryFrom < u64 > >:: Error ;
176
+ fn try_from ( x : u64 ) -> std:: result:: Result < Self , Self :: Error > {
177
+ Ok ( Self ( i32:: try_from ( x) ?) )
178
+ }
179
+ }
180
+ impl TryFrom < u32 > for PollTimeout {
181
+ type Error = <i32 as TryFrom < u32 > >:: Error ;
182
+ fn try_from ( x : u32 ) -> std:: result:: Result < Self , Self :: Error > {
183
+ Ok ( Self ( i32:: try_from ( x) ?) )
184
+ }
185
+ }
186
+ impl From < u16 > for PollTimeout {
187
+ fn from ( x : u16 ) -> Self {
188
+ Self ( i32:: from ( x) )
189
+ }
190
+ }
191
+ impl From < u8 > for PollTimeout {
192
+ fn from ( x : u8 ) -> Self {
193
+ Self ( i32:: from ( x) )
194
+ }
195
+ }
196
+ impl TryFrom < i128 > for PollTimeout {
197
+ type Error = <i32 as TryFrom < i128 > >:: Error ;
198
+ fn try_from ( x : i128 ) -> std:: result:: Result < Self , Self :: Error > {
199
+ match x {
200
+ // > Specifying a negative value in timeout means an infinite timeout.
201
+ i128:: MIN ..=-1 => Ok ( Self :: NONE ) ,
202
+ millis @ 0 .. => Ok ( Self (
203
+ i32:: try_from ( millis) ?,
204
+ ) ) ,
205
+ }
206
+ }
207
+ }
208
+ impl TryFrom < i64 > for PollTimeout {
209
+ type Error = <i32 as TryFrom < i64 > >:: Error ;
210
+ fn try_from ( x : i64 ) -> std:: result:: Result < Self , Self :: Error > {
211
+ match x {
212
+ i64:: MIN ..=-1 => Ok ( Self :: NONE ) ,
213
+ millis @ 0 .. => Ok ( Self (
214
+ i32:: try_from ( millis) ?,
215
+ ) ) ,
216
+ }
217
+ }
218
+ }
219
+ impl From < i32 > for PollTimeout {
220
+ fn from ( millis : i32 ) -> Self {
221
+ Self ( millis)
222
+ }
223
+ }
224
+ impl TryFrom < i16 > for PollTimeout {
225
+ type Error = Errno ;
226
+ fn try_from ( x : i16 ) -> Result < Self > {
227
+ match x {
228
+ -1 => Ok ( Self :: NONE ) ,
229
+ millis @ 0 .. => Ok ( Self ( millis. into ( ) ) ) ,
230
+ // EINVAL (ppoll()) The timeout value expressed in *ip is invalid (negative).
231
+ _ => Err ( Errno :: EINVAL ) ,
232
+ }
233
+ }
234
+ }
235
+ impl TryFrom < i8 > for PollTimeout {
236
+ type Error = Errno ;
237
+ fn try_from ( x : i8 ) -> Result < Self > {
238
+ match x {
239
+ -1 => Ok ( Self :: NONE ) ,
240
+ millis @ 0 .. => Ok ( Self ( millis. into ( ) ) ) ,
241
+ // EINVAL (ppoll()) The timeout value expressed in *ip is invalid (negative).
242
+ _ => Err ( Errno :: EINVAL ) ,
243
+ }
244
+ }
245
+ }
246
+ impl TryFrom < PollTimeout > for Duration {
247
+ type Error = ( ) ;
248
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , ( ) > {
249
+ match x. timeout ( ) {
250
+ // SAFETY: When `x.timeout()` returns `Some(a)`, `a` is always non-negative.
251
+ Some ( millis) => Ok ( Duration :: from_millis ( unsafe {
252
+ u64:: try_from ( millis) . unwrap_unchecked ( )
253
+ } ) ) ,
254
+ None => Err ( ( ) ) ,
255
+ }
256
+ }
257
+ }
258
+ impl TryFrom < PollTimeout > for u128 {
259
+ type Error = <Self as TryFrom < i32 > >:: Error ;
260
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
261
+ Self :: try_from ( x. 0 )
262
+ }
263
+ }
264
+ impl TryFrom < PollTimeout > for u64 {
265
+ type Error = <Self as TryFrom < i32 > >:: Error ;
266
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
267
+ Self :: try_from ( x. 0 )
268
+ }
269
+ }
270
+ impl TryFrom < PollTimeout > for u32 {
271
+ type Error = <Self as TryFrom < i32 > >:: Error ;
272
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
273
+ Self :: try_from ( x. 0 )
274
+ }
275
+ }
276
+ impl TryFrom < PollTimeout > for u16 {
277
+ type Error = Option < <Self as TryFrom < i32 > >:: Error > ;
278
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
279
+ match x. timeout ( ) {
280
+ Some ( millis) => Ok ( Self :: try_from ( millis) . map_err ( Some ) ?) ,
281
+ None => Err ( None ) ,
282
+ }
283
+ }
284
+ }
285
+ impl TryFrom < PollTimeout > for u8 {
286
+ type Error = Option < <Self as TryFrom < i32 > >:: Error > ;
287
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
288
+ match x. timeout ( ) {
289
+ Some ( millis) => Ok ( Self :: try_from ( millis) . map_err ( Some ) ?) ,
290
+ None => Err ( None ) ,
291
+ }
292
+ }
293
+ }
294
+ impl From < PollTimeout > for i128 {
295
+ fn from ( x : PollTimeout ) -> Self {
296
+ x. timeout ( ) . unwrap_or ( -1 ) . into ( )
297
+ }
298
+ }
299
+ impl From < PollTimeout > for i64 {
300
+ fn from ( x : PollTimeout ) -> Self {
301
+ x. timeout ( ) . unwrap_or ( -1 ) . into ( )
302
+ }
303
+ }
304
+ impl From < PollTimeout > for i32 {
305
+ fn from ( x : PollTimeout ) -> Self {
306
+ x. timeout ( ) . unwrap_or ( -1 )
307
+ }
308
+ }
309
+ impl TryFrom < PollTimeout > for i16 {
310
+ type Error = <Self as TryFrom < i32 > >:: Error ;
311
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
312
+ Self :: try_from ( x. timeout ( ) . unwrap_or ( -1 ) )
313
+ }
314
+ }
315
+ impl TryFrom < PollTimeout > for i8 {
316
+ type Error = <Self as TryFrom < i32 > >:: Error ;
317
+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
318
+ Self :: try_from ( x. timeout ( ) . unwrap_or ( -1 ) )
319
+ }
320
+ }
321
+
135
322
/// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
136
323
/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
137
324
///
@@ -148,16 +335,16 @@ libc_bitflags! {
148
335
///
149
336
/// Note that the timeout interval will be rounded up to the system clock
150
337
/// granularity, and kernel scheduling delays mean that the blocking
151
- /// interval may overrun by a small amount. Specifying a negative value
152
- /// in timeout means an infinite timeout. Specifying a timeout of zero
153
- /// causes `poll()` to return immediately, even if no file descriptors are
154
- /// ready.
155
- pub fn poll ( fds : & mut [ PollFd ] , timeout : libc :: c_int ) -> Result < libc:: c_int > {
338
+ /// interval may overrun by a small amount. Specifying a [`PollTimeout::NONE`]
339
+ /// in timeout means an infinite timeout. Specifying a timeout of
340
+ /// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file
341
+ /// descriptors are ready.
342
+ pub fn poll < T : Into < PollTimeout > > ( fds : & mut [ PollFd ] , timeout : T ) -> Result < libc:: c_int > {
156
343
let res = unsafe {
157
344
libc:: poll (
158
345
fds. as_mut_ptr ( ) as * mut libc:: pollfd ,
159
346
fds. len ( ) as libc:: nfds_t ,
160
- timeout,
347
+ i32 :: from ( timeout. into ( ) ) ,
161
348
)
162
349
} ;
163
350
0 commit comments