base_coroutine/event_loop/event/
event.rs

1use crate::event_loop::selector as sys;
2
3use std::fmt;
4
5/// A readiness event.
6///
7/// `Event` is a readiness state paired with a [`Token`]. It is returned by
8/// [`Poll::poll`].
9///
10/// For more documentation on polling and events, see [`Poll`].
11///
12/// [`Poll::poll`]: ../struct.Poll.html#method.poll
13/// [`Poll`]: ../struct.Poll.html
14/// [`Token`]: ../struct.Token.html
15#[derive(Clone)]
16#[repr(transparent)]
17pub struct Event {
18    inner: sys::Event,
19}
20
21impl Event {
22    /// Returns the event's fd.
23    pub fn fd(&self) -> libc::c_int {
24        sys::event::fd(&self.inner)
25    }
26
27    /// Returns the event's token.
28    pub fn token(&self) -> usize {
29        sys::event::token(&self.inner)
30    }
31
32    /// Returns true if the event contains readable readiness.
33    ///
34    /// # Notes
35    ///
36    /// Out-of-band (OOB) data also triggers readable events. But must
37    /// application don't actually read OOB data, this could leave an
38    /// application open to a Denial-of-Service (Dos) attack, see
39    /// <https://github.com/sandstorm-io/sandstorm-website/blob/58f93346028c0576e8147627667328eaaf4be9fa/_posts/2015-04-08-osx-security-bug.md>.
40    /// However because Mio uses edge-triggers it will not result in an infinite
41    /// loop as described in the article above.
42    pub fn is_readable(&self) -> bool {
43        sys::event::is_readable(&self.inner)
44    }
45
46    /// Returns true if the event contains writable readiness.
47    pub fn is_writable(&self) -> bool {
48        sys::event::is_writable(&self.inner)
49    }
50
51    /// Returns true if the event contains error readiness.
52    ///
53    /// Error events occur when the socket enters an error state. In this case,
54    /// the socket will also receive a readable or writable event. Reading or
55    /// writing to the socket will result in an error.
56    ///
57    /// # Notes
58    ///
59    /// Method is available on all platforms, but not all platforms trigger the
60    /// error event.
61    ///
62    /// The table below shows what flags are checked on what OS.
63    ///
64    /// | [OS selector] | Flag(s) checked |
65    /// |---------------|-----------------|
66    /// | [epoll]       | `EPOLLERR`      |
67    /// | [kqueue]      | `EV_ERROR` and `EV_EOF` with `fflags` set to `0`. |
68    ///
69    /// [OS selector]: ../struct.Poll.html#implementation-notes
70    /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html
71    /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
72    pub fn is_error(&self) -> bool {
73        sys::event::is_error(&self.inner)
74    }
75
76    /// Returns true if the event contains read closed readiness.
77    ///
78    /// # Notes
79    ///
80    /// Read closed readiness can be expected after any of the following have
81    /// occurred:
82    /// * The local stream has shutdown the read half of its socket
83    /// * The local stream has shutdown both the read half and the write half
84    ///   of its socket
85    /// * The peer stream has shutdown the write half its socket; this sends a
86    ///   `FIN` packet that has been received by the local stream
87    ///
88    /// Method is a best effort implementation. While some platforms may not
89    /// return readiness when read half is closed, it is guaranteed that
90    /// false-positives will not occur.
91    ///
92    /// The table below shows what flags are checked on what OS.
93    ///
94    /// | [OS selector] | Flag(s) checked |
95    /// |---------------|-----------------|
96    /// | [epoll]       | `EPOLLHUP`, or  |
97    /// |               | `EPOLLIN` and `EPOLLRDHUP` |
98    /// | [kqueue]      | `EV_EOF`        |
99    ///
100    /// [OS selector]: ../struct.Poll.html#implementation-notes
101    /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html
102    /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
103    pub fn is_read_closed(&self) -> bool {
104        sys::event::is_read_closed(&self.inner)
105    }
106
107    /// Returns true if the event contains write closed readiness.
108    ///
109    /// # Notes
110    ///
111    /// On [epoll] this is essentially a check for `EPOLLHUP` flag as the
112    /// local stream shutting down its write half does not trigger this event.
113    ///
114    /// On [kqueue] the local stream shutting down the write half of its
115    /// socket will trigger this event.
116    ///
117    /// Method is a best effort implementation. While some platforms may not
118    /// return readiness when write half is closed, it is guaranteed that
119    /// false-positives will not occur.
120    ///
121    /// The table below shows what flags are checked on what OS.
122    ///
123    /// | [OS selector] | Flag(s) checked |
124    /// |---------------|-----------------|
125    /// | [epoll]       | `EPOLLHUP`, or  |
126    /// |               | only `EPOLLERR`, or |
127    /// |               | `EPOLLOUT` and `EPOLLERR` |
128    /// | [kqueue]      | `EV_EOF`        |
129    ///
130    /// [OS selector]: ../struct.Poll.html#implementation-notes
131    /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html
132    /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
133    pub fn is_write_closed(&self) -> bool {
134        sys::event::is_write_closed(&self.inner)
135    }
136
137    /// Returns true if the event contains priority readiness.
138    ///
139    /// # Notes
140    ///
141    /// Method is available on all platforms, but not all platforms trigger the
142    /// priority event.
143    ///
144    /// The table below shows what flags are checked on what OS.
145    ///
146    /// | [OS selector] | Flag(s) checked |
147    /// |---------------|-----------------|
148    /// | [epoll]       | `EPOLLPRI`      |
149    /// | [kqueue]      | *Not supported* |
150    ///
151    /// [OS selector]: ../struct.Poll.html#implementation-notes
152    /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html
153    /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
154    #[inline]
155    pub fn is_priority(&self) -> bool {
156        sys::event::is_priority(&self.inner)
157    }
158
159    /// Returns true if the event contains AIO readiness.
160    ///
161    /// # Notes
162    ///
163    /// Method is available on all platforms, but not all platforms support AIO.
164    ///
165    /// The table below shows what flags are checked on what OS.
166    ///
167    /// | [OS selector] | Flag(s) checked |
168    /// |---------------|-----------------|
169    /// | [epoll]       | *Not supported* |
170    /// | [kqueue]<sup>1</sup> | `EVFILT_AIO` |
171    ///
172    /// 1: Only supported on DragonFly BSD, FreeBSD, iOS and macOS.
173    ///
174    /// [OS selector]: ../struct.Poll.html#implementation-notes
175    /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html
176    /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
177    pub fn is_aio(&self) -> bool {
178        sys::event::is_aio(&self.inner)
179    }
180
181    /// Returns true if the event contains LIO readiness.
182    ///
183    /// # Notes
184    ///
185    /// Method is available on all platforms, but only FreeBSD supports LIO. On
186    /// FreeBSD this method checks the `EVFILT_LIO` flag.
187    pub fn is_lio(&self) -> bool {
188        sys::event::is_lio(&self.inner)
189    }
190
191    /// Create a reference to an `Event` from a platform specific event.
192    pub(crate) fn from_sys_event_ref(sys_event: &sys::Event) -> &Event {
193        unsafe {
194            // This is safe because the memory layout of `Event` is
195            // the same as `sys::Event` due to the `repr(transparent)` attribute.
196            &*(sys_event as *const sys::Event as *const Event)
197        }
198    }
199}
200
201/// When the [alternate] flag is enabled this will print platform specific
202/// details, for example the fields of the `kevent` structure on platforms that
203/// use `kqueue(2)`. Note however that the output of this implementation is
204/// **not** consider a part of the stable API.
205///
206/// [alternate]: fmt::Formatter::alternate
207impl fmt::Debug for Event {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        let alternate = f.alternate();
210        let mut d = f.debug_struct("Event");
211        d.field("fd", &self.fd())
212            .field("token", &self.token())
213            .field("readable", &self.is_readable())
214            .field("writable", &self.is_writable())
215            .field("error", &self.is_error())
216            .field("read_closed", &self.is_read_closed())
217            .field("write_closed", &self.is_write_closed())
218            .field("priority", &self.is_priority())
219            .field("aio", &self.is_aio())
220            .field("lio", &self.is_lio());
221
222        if alternate {
223            struct EventDetails<'a>(&'a sys::Event);
224
225            impl<'a> fmt::Debug for EventDetails<'a> {
226                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227                    sys::event::debug_details(f, self.0)
228                }
229            }
230
231            d.field("details", &EventDetails(&self.inner)).finish()
232        } else {
233            d.finish()
234        }
235    }
236}