1
1
//! 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 } ;
3
3
4
4
use crate :: errno:: Errno ;
5
5
use crate :: Result ;
@@ -14,20 +14,36 @@ use crate::Result;
14
14
/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
15
15
#[ repr( transparent) ]
16
16
#[ derive( Clone , Copy , Debug , Eq , Hash , PartialEq ) ]
17
- pub struct PollFd {
17
+ pub struct PollFd < ' fd > {
18
18
pollfd : libc:: pollfd ,
19
+ _fd : std:: marker:: PhantomData < BorrowedFd < ' fd > >
19
20
}
20
21
21
- impl PollFd {
22
+ impl < ' fd > PollFd < ' fd > {
22
23
/// Creates a new `PollFd` specifying the events of interest
23
24
/// 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 > {
25
40
PollFd {
26
41
pollfd : libc:: pollfd {
27
- fd,
42
+ fd : fd . as_fd ( ) . as_raw_fd ( ) ,
28
43
events : events. bits ( ) ,
29
44
revents : PollFlags :: empty ( ) . bits ( ) ,
30
45
} ,
46
+ _fd : std:: marker:: PhantomData ,
31
47
}
32
48
}
33
49
@@ -68,9 +84,29 @@ impl PollFd {
68
84
}
69
85
}
70
86
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 ) }
74
110
}
75
111
}
76
112
0 commit comments