11//! Wait for events to trigger on specific file descriptors
2- use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
2+ use std:: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd } ;
33
44use crate :: errno:: Errno ;
55use crate :: Result ;
@@ -14,20 +14,36 @@ use crate::Result;
1414/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
1515#[ repr( transparent) ]
1616#[ derive( Clone , Copy , Debug , Eq , Hash , PartialEq ) ]
17- pub struct PollFd {
17+ pub struct PollFd < ' fd > {
1818 pollfd : libc:: pollfd ,
19+ _fd : std:: marker:: PhantomData < BorrowedFd < ' fd > > ,
1920}
2021
21- impl PollFd {
22+ impl < ' fd > PollFd < ' fd > {
2223 /// Creates a new `PollFd` specifying the events of interest
2324 /// for a given file descriptor.
24- pub const fn new ( fd : RawFd , events : PollFlags ) -> PollFd {
25+ //
26+ // Different from other I/O-safe interfaces, here, we have to take `AsFd`
27+ // by reference to prevent the case where the `fd` is closed but it is
28+ // still in use. For example:
29+ //
30+ // ```rust
31+ // let (reader, _) = pipe().unwrap();
32+ //
33+ // // If `PollFd::new()` takes `AsFd` by value, then `reader` will be consumed,
34+ // // but the file descriptor of `reader` will still be in use.
35+ // let pollfd = PollFd::new(reader, flag);
36+ //
37+ // // Do something with `pollfd`, which uses the CLOSED fd.
38+ // ```
39+ pub fn new < Fd : AsFd > ( fd : & ' fd Fd , events : PollFlags ) -> PollFd < ' fd > {
2540 PollFd {
2641 pollfd : libc:: pollfd {
27- fd,
42+ fd : fd . as_fd ( ) . as_raw_fd ( ) ,
2843 events : events. bits ( ) ,
2944 revents : PollFlags :: empty ( ) . bits ( ) ,
3045 } ,
46+ _fd : std:: marker:: PhantomData ,
3147 }
3248 }
3349
@@ -68,9 +84,29 @@ impl PollFd {
6884 }
6985}
7086
71- impl AsRawFd for PollFd {
72- fn as_raw_fd ( & self ) -> RawFd {
73- self . pollfd . fd
87+ impl < ' fd > AsFd for PollFd < ' fd > {
88+ fn as_fd ( & self ) -> BorrowedFd < ' _ > {
89+ // Safety:
90+ //
91+ // BorrowedFd::borrow_raw(RawFd) requires that the raw fd being passed
92+ // must remain open for the duration of the returned BorrowedFd, this is
93+ // guaranteed as the returned BorrowedFd has the lifetime parameter same
94+ // as `self`:
95+ // "fn as_fd<'self>(&'self self) -> BorrowedFd<'self>"
96+ // which means that `self` (PollFd) is guaranteed to outlive the returned
97+ // BorrowedFd. (Lifetime: PollFd > BorrowedFd)
98+ //
99+ // And the lifetime parameter of PollFd::new(fd, ...) ensures that `fd`
100+ // (an owned file descriptor) must outlive the returned PollFd:
101+ // "pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd>"
102+ // (Lifetime: Owned fd > PollFd)
103+ //
104+ // With two above relationships, we can conclude that the `Owned file
105+ // descriptor` will outlive the returned BorrowedFd,
106+ // (Lifetime: Owned fd > BorrowedFd)
107+ // i.e., the raw fd being passed will remain valid for the lifetime of
108+ // the returned BorrowedFd.
109+ unsafe { BorrowedFd :: borrow_raw ( self . pollfd . fd ) }
74110 }
75111}
76112
0 commit comments