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}