11//! Wait for events to trigger on specific file descriptors
22use std:: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd } ;
3+ use std:: time:: Duration ;
34
45use crate :: errno:: Errno ;
56use crate :: Result ;
6-
77/// This is a wrapper around `libc::pollfd`.
88///
99/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
@@ -27,13 +27,13 @@ impl<'fd> PollFd<'fd> {
2727 /// ```no_run
2828 /// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd};
2929 /// # use nix::{
30- /// # poll::{PollFd, PollFlags, poll},
30+ /// # poll::{PollTimeout, PollFd, PollFlags, poll},
3131 /// # unistd::{pipe, read}
3232 /// # };
3333 /// let (r, w) = pipe().unwrap();
3434 /// let pfd = PollFd::new(r.as_fd(), PollFlags::POLLIN);
3535 /// let mut fds = [pfd];
36- /// poll(&mut fds, -1 ).unwrap();
36+ /// poll(&mut fds, PollTimeout::NONE ).unwrap();
3737 /// let mut buf = [0u8; 80];
3838 /// read(r.as_raw_fd(), &mut buf[..]);
3939 /// ```
@@ -175,6 +175,210 @@ libc_bitflags! {
175175 }
176176}
177177
178+ /// Timeout argument for [`poll`].
179+ #[ derive( Debug , Clone , Copy , Eq , PartialEq , Ord , PartialOrd ) ]
180+ pub struct PollTimeout ( i32 ) ;
181+
182+ impl PollTimeout {
183+ /// Blocks indefinitely.
184+ ///
185+ /// > Specifying a negative value in timeout means an infinite timeout.
186+ pub const NONE : Self = Self ( -1 ) ;
187+ /// Returns immediately.
188+ ///
189+ /// > Specifying a timeout of zero causes poll() to return immediately, even if no file
190+ /// > descriptors are ready.
191+ pub const ZERO : Self = Self ( 0 ) ;
192+ /// Blocks for at most [`std::i32::MAX`] milliseconds.
193+ pub const MAX : Self = Self ( i32:: MAX ) ;
194+ /// Returns if `self` equals [`PollTimeout::NONE`].
195+ pub fn is_none ( & self ) -> bool {
196+ // > Specifying a negative value in timeout means an infinite timeout.
197+ * self <= Self :: NONE
198+ }
199+ /// Returns if `self` does not equal [`PollTimeout::NONE`].
200+ pub fn is_some ( & self ) -> bool {
201+ !self . is_none ( )
202+ }
203+ /// Returns the timeout in milliseconds if there is some, otherwise returns `None`.
204+ pub fn as_millis ( & self ) -> Option < i32 > {
205+ self . is_some ( ) . then_some ( self . 0 )
206+ }
207+ /// Returns the timeout as a `Duration` if there is some, otherwise returns `None`.
208+ pub fn timeout ( & self ) -> Option < Duration > {
209+ self . as_millis ( ) . map ( |x|Duration :: from_millis ( u64:: try_from ( x) . unwrap ( ) ) )
210+ }
211+ }
212+
213+ /// Error type for integer conversions into `PollTimeout`.
214+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
215+ pub enum PollTimeoutTryFromError {
216+ /// Passing a value less than -1 is invalid on some systems, see
217+ /// <https://man.freebsd.org/cgi/man.cgi?poll#end>.
218+ TooNegative ,
219+ /// Passing a value greater than `i32::MAX` is invalid.
220+ TooPositive ,
221+ }
222+
223+ impl std:: fmt:: Display for PollTimeoutTryFromError {
224+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
225+ match self {
226+ Self :: TooNegative => write ! ( f, "Passed a negative timeout less than -1." ) ,
227+ Self :: TooPositive => write ! ( f, "Passed a positive timeout greater than `i32::MAX` milliseconds." )
228+ }
229+ }
230+ }
231+
232+ impl std:: error:: Error for PollTimeoutTryFromError { }
233+
234+ impl < T : Into < PollTimeout > > From < Option < T > > for PollTimeout {
235+ fn from ( x : Option < T > ) -> Self {
236+ x. map_or ( Self :: NONE , |x| x. into ( ) )
237+ }
238+ }
239+ impl TryFrom < Duration > for PollTimeout {
240+ type Error = PollTimeoutTryFromError ;
241+ fn try_from ( x : Duration ) -> std:: result:: Result < Self , Self :: Error > {
242+ Ok ( Self ( i32:: try_from ( x. as_millis ( ) ) . map_err ( |_|PollTimeoutTryFromError :: TooPositive ) ?) )
243+ }
244+ }
245+ impl TryFrom < u128 > for PollTimeout {
246+ type Error = PollTimeoutTryFromError ;
247+ fn try_from ( x : u128 ) -> std:: result:: Result < Self , Self :: Error > {
248+ Ok ( Self ( i32:: try_from ( x) . map_err ( |_|PollTimeoutTryFromError :: TooPositive ) ?) )
249+ }
250+ }
251+ impl TryFrom < u64 > for PollTimeout {
252+ type Error = PollTimeoutTryFromError ;
253+ fn try_from ( x : u64 ) -> std:: result:: Result < Self , Self :: Error > {
254+ Ok ( Self ( i32:: try_from ( x) . map_err ( |_|PollTimeoutTryFromError :: TooPositive ) ?) )
255+ }
256+ }
257+ impl TryFrom < u32 > for PollTimeout {
258+ type Error = PollTimeoutTryFromError ;
259+ fn try_from ( x : u32 ) -> std:: result:: Result < Self , Self :: Error > {
260+ Ok ( Self ( i32:: try_from ( x) . map_err ( |_|PollTimeoutTryFromError :: TooPositive ) ?) )
261+ }
262+ }
263+ impl From < u16 > for PollTimeout {
264+ fn from ( x : u16 ) -> Self {
265+ Self ( i32:: from ( x) )
266+ }
267+ }
268+ impl From < u8 > for PollTimeout {
269+ fn from ( x : u8 ) -> Self {
270+ Self ( i32:: from ( x) )
271+ }
272+ }
273+ impl TryFrom < i128 > for PollTimeout {
274+ type Error = PollTimeoutTryFromError ;
275+ fn try_from ( x : i128 ) -> std:: result:: Result < Self , Self :: Error > {
276+ match x {
277+ ..=-2 => Err ( PollTimeoutTryFromError :: TooNegative ) ,
278+ -1 .. => Ok ( Self ( i32:: try_from ( x) . map_err ( |_|PollTimeoutTryFromError :: TooPositive ) ?) ) ,
279+ }
280+ }
281+ }
282+ impl TryFrom < i64 > for PollTimeout {
283+ type Error = PollTimeoutTryFromError ;
284+ fn try_from ( x : i64 ) -> std:: result:: Result < Self , Self :: Error > {
285+ match x {
286+ ..=-2 => Err ( PollTimeoutTryFromError :: TooNegative ) ,
287+ -1 .. => Ok ( Self ( i32:: try_from ( x) . map_err ( |_|PollTimeoutTryFromError :: TooPositive ) ?) ) ,
288+ }
289+ }
290+ }
291+ impl TryFrom < i32 > for PollTimeout {
292+ type Error = PollTimeoutTryFromError ;
293+ fn try_from ( x : i32 ) -> std:: result:: Result < Self , Self :: Error > {
294+ match x {
295+ ..=-2 => Err ( PollTimeoutTryFromError :: TooNegative ) ,
296+ -1 .. => Ok ( Self ( x) ) ,
297+ }
298+ }
299+ }
300+ impl TryFrom < i16 > for PollTimeout {
301+ type Error = PollTimeoutTryFromError ;
302+ fn try_from ( x : i16 ) -> std:: result:: Result < Self , Self :: Error > {
303+ match x {
304+ ..=-2 => Err ( PollTimeoutTryFromError :: TooNegative ) ,
305+ -1 .. => Ok ( Self ( i32:: from ( x) ) ) ,
306+ }
307+ }
308+ }
309+ impl TryFrom < i8 > for PollTimeout {
310+ type Error = PollTimeoutTryFromError ;
311+ fn try_from ( x : i8 ) -> std:: result:: Result < Self , Self :: Error > {
312+ match x {
313+ ..=-2 => Err ( PollTimeoutTryFromError :: TooNegative ) ,
314+ -1 .. => Ok ( Self ( i32:: from ( x) ) ) ,
315+ }
316+ }
317+ }
318+ impl TryFrom < PollTimeout > for Duration {
319+ type Error = ( ) ;
320+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , ( ) > {
321+ x. timeout ( ) . ok_or ( ( ) )
322+ }
323+ }
324+ impl TryFrom < PollTimeout > for u128 {
325+ type Error = <Self as TryFrom < i32 > >:: Error ;
326+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
327+ Self :: try_from ( x. 0 )
328+ }
329+ }
330+ impl TryFrom < PollTimeout > for u64 {
331+ type Error = <Self as TryFrom < i32 > >:: Error ;
332+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
333+ Self :: try_from ( x. 0 )
334+ }
335+ }
336+ impl TryFrom < PollTimeout > for u32 {
337+ type Error = <Self as TryFrom < i32 > >:: Error ;
338+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
339+ Self :: try_from ( x. 0 )
340+ }
341+ }
342+ impl TryFrom < PollTimeout > for u16 {
343+ type Error = <Self as TryFrom < i32 > >:: Error ;
344+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
345+ Self :: try_from ( x. 0 )
346+ }
347+ }
348+ impl TryFrom < PollTimeout > for u8 {
349+ type Error = <Self as TryFrom < i32 > >:: Error ;
350+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
351+ Self :: try_from ( x. 0 )
352+ }
353+ }
354+ impl From < PollTimeout > for i128 {
355+ fn from ( x : PollTimeout ) -> Self {
356+ Self :: from ( x. 0 )
357+ }
358+ }
359+ impl From < PollTimeout > for i64 {
360+ fn from ( x : PollTimeout ) -> Self {
361+ Self :: from ( x. 0 )
362+ }
363+ }
364+ impl From < PollTimeout > for i32 {
365+ fn from ( x : PollTimeout ) -> Self {
366+ x. 0
367+ }
368+ }
369+ impl TryFrom < PollTimeout > for i16 {
370+ type Error = <Self as TryFrom < i32 > >:: Error ;
371+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
372+ Self :: try_from ( x. 0 )
373+ }
374+ }
375+ impl TryFrom < PollTimeout > for i8 {
376+ type Error = <Self as TryFrom < i32 > >:: Error ;
377+ fn try_from ( x : PollTimeout ) -> std:: result:: Result < Self , Self :: Error > {
378+ Self :: try_from ( x. 0 )
379+ }
380+ }
381+
178382/// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
179383/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
180384///
@@ -191,13 +395,20 @@ libc_bitflags! {
191395///
192396/// Note that the timeout interval will be rounded up to the system clock
193397/// granularity, and kernel scheduling delays mean that the blocking
194- /// interval may overrun by a small amount. Specifying a negative value
195- /// in timeout means an infinite timeout. Specifying a timeout of zero
196- /// causes `poll()` to return immediately, even if no file descriptors are
197- /// ready.
198- pub fn poll ( fds : & mut [ PollFd ] , timeout : libc:: c_int ) -> Result < libc:: c_int > {
398+ /// interval may overrun by a small amount. Specifying a [`PollTimeout::NONE`]
399+ /// in timeout means an infinite timeout. Specifying a timeout of
400+ /// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file
401+ /// descriptors are ready.
402+ pub fn poll < T : Into < PollTimeout > > (
403+ fds : & mut [ PollFd ] ,
404+ timeout : T ,
405+ ) -> Result < libc:: c_int > {
199406 let res = unsafe {
200- libc:: poll ( fds. as_mut_ptr ( ) . cast ( ) , fds. len ( ) as libc:: nfds_t , timeout)
407+ libc:: poll (
408+ fds. as_mut_ptr ( ) . cast ( ) ,
409+ fds. len ( ) as libc:: nfds_t ,
410+ i32:: from ( timeout. into ( ) ) ,
411+ )
201412 } ;
202413
203414 Errno :: result ( res)
0 commit comments