pal_async/
interest.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Types related to event interests.
5
6use crate::waker::WakerList;
7use std::fmt;
8use std::fmt::Debug;
9use std::task::Context;
10use std::task::Poll;
11use std::task::Waker;
12
13/// A set of readiness events for polled IO.
14#[derive(Copy, Clone, Default, PartialEq, Eq)]
15pub struct PollEvents(u32);
16
17impl Debug for PollEvents {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        let mut list = f.debug_set();
20        if self.has_in() {
21            list.entry(&format_args!("IN"));
22        }
23        if self.has_out() {
24            list.entry(&format_args!("OUT"));
25        }
26        if self.has_err() {
27            list.entry(&format_args!("ERR"));
28        }
29        if self.has_hup() {
30            list.entry(&format_args!("HUP"));
31        }
32        if self.has_pri() {
33            list.entry(&format_args!("PRI"));
34        }
35        #[cfg(any(windows, target_os = "linux"))]
36        if self.has_rdhup() {
37            list.entry(&format_args!("RDHUP"));
38        }
39        list.finish()
40    }
41}
42
43impl PollEvents {
44    /// The empty set.
45    pub const EMPTY: Self = Self(0);
46    /// The full set.
47    pub const FULL: Self = Self(0x3f);
48    /// Read readiness, corresponding to `POLLIN`.
49    pub const IN: Self = Self(0x1);
50    /// Write readiness, corresponding to `POLLOUT`.
51    pub const OUT: Self = Self(0x2);
52    /// An error condition, corresponding to `POLLERR`.
53    pub const ERR: Self = Self(0x4);
54    /// Hangup, corresponding to `POLLHUP`. The behavior of this depends on the object.
55    pub const HUP: Self = Self(0x8);
56    /// Priority data readiness, corresponding to `POLLPRI`.
57    pub const PRI: Self = Self(0x10);
58    /// Read hangup, corresponding to `POLLRDHUP`.
59    pub const RDHUP: Self = Self(0x20);
60
61    /// Returns whether the set is empty.
62    pub fn is_empty(self) -> bool {
63        self.0 == 0
64    }
65
66    /// Returns whether the set includes `IN`.
67    pub fn has_in(self) -> bool {
68        self.0 & Self::IN.0 != 0
69    }
70
71    /// Returns whether the set includes `OUT`.
72    pub fn has_out(self) -> bool {
73        self.0 & Self::OUT.0 != 0
74    }
75
76    /// Returns whether the set includes `ERR`.
77    pub fn has_err(self) -> bool {
78        self.0 & Self::ERR.0 != 0
79    }
80
81    /// Returns whether the set includes `HUP`.
82    pub fn has_hup(self) -> bool {
83        self.0 & Self::HUP.0 != 0
84    }
85
86    /// Returns whether the set includes `PRI`.
87    pub fn has_pri(self) -> bool {
88        self.0 & Self::PRI.0 != 0
89    }
90
91    /// Returns whether the set includes `RDHUP`.
92    #[cfg(any(windows, target_os = "linux"))]
93    pub fn has_rdhup(self) -> bool {
94        self.0 & Self::RDHUP.0 != 0
95    }
96}
97
98impl std::ops::Not for PollEvents {
99    type Output = Self;
100
101    fn not(self) -> Self::Output {
102        Self(!self.0) & Self::FULL
103    }
104}
105
106impl std::ops::BitOr for PollEvents {
107    type Output = Self;
108
109    fn bitor(self, rhs: Self) -> Self::Output {
110        Self(self.0 | rhs.0)
111    }
112}
113
114impl std::ops::BitOrAssign for PollEvents {
115    fn bitor_assign(&mut self, rhs: Self) {
116        self.0 |= rhs.0;
117    }
118}
119
120impl std::ops::BitAnd for PollEvents {
121    type Output = Self;
122
123    fn bitand(self, rhs: Self) -> Self::Output {
124        Self(self.0 & rhs.0)
125    }
126}
127
128impl std::ops::BitAndAssign for PollEvents {
129    fn bitand_assign(&mut self, rhs: Self) {
130        self.0 &= rhs.0;
131    }
132}
133
134impl PollEvents {
135    /// Converts to the platform-specific poll events.
136    #[cfg(unix)]
137    pub fn to_poll_events(self) -> i16 {
138        let mut poll_events = 0;
139        if self.has_in() {
140            poll_events |= libc::POLLIN;
141        }
142        if self.has_out() {
143            poll_events |= libc::POLLOUT;
144        }
145        if self.has_pri() {
146            poll_events |= libc::POLLPRI;
147        }
148        if self.has_hup() {
149            poll_events |= libc::POLLHUP;
150        }
151        if self.has_err() {
152            poll_events |= libc::POLLERR;
153        }
154        #[cfg(target_os = "linux")]
155        if self.has_rdhup() {
156            poll_events |= libc::POLLRDHUP;
157        }
158        poll_events
159    }
160
161    /// Converts from the platform-specific poll events.
162    #[cfg(unix)]
163    pub fn from_poll_events(poll_events: i16) -> Self {
164        let mut events = PollEvents::EMPTY;
165        if poll_events & libc::POLLHUP != 0 {
166            events |= PollEvents::HUP;
167        }
168        if poll_events & libc::POLLERR != 0 {
169            events |= PollEvents::ERR;
170        }
171        if poll_events & libc::POLLIN != 0 {
172            events |= PollEvents::IN;
173        }
174        if poll_events & libc::POLLOUT != 0 {
175            events |= PollEvents::OUT;
176        }
177        if poll_events & libc::POLLPRI != 0 {
178            events |= PollEvents::PRI;
179        }
180        #[cfg(target_os = "linux")]
181        if poll_events & libc::POLLRDHUP != 0 {
182            events |= PollEvents::RDHUP;
183        }
184        events
185    }
186
187    #[cfg(target_os = "linux")]
188    pub(crate) fn from_epoll_events(epoll_events: u32) -> Self {
189        let mut events = PollEvents::EMPTY;
190        if epoll_events & libc::EPOLLIN as u32 != 0 {
191            events |= PollEvents::IN;
192        }
193        if epoll_events & libc::EPOLLOUT as u32 != 0 {
194            events |= PollEvents::OUT;
195        }
196        if epoll_events & libc::EPOLLERR as u32 != 0 {
197            events |= PollEvents::ERR;
198        }
199        if epoll_events & libc::EPOLLHUP as u32 != 0 {
200            events |= PollEvents::HUP;
201        }
202        if epoll_events & libc::EPOLLPRI as u32 != 0 {
203            events |= PollEvents::PRI;
204        }
205        if epoll_events & libc::EPOLLRDHUP as u32 != 0 {
206            events |= PollEvents::RDHUP;
207        }
208        events
209    }
210}
211
212#[derive(Debug, Default)]
213struct PollInterest {
214    events: PollEvents,
215    observed_revents: PollEvents,
216    delivered_revents: PollEvents,
217    waker: Option<Waker>,
218}
219
220/// The interest slot.
221///
222/// Sockets, fds, and waits can have multiple concurrent outstanding polls,
223/// allowing a read and write operation to be polled concurrently, for example.
224/// This enum is used to distinguish between the multiple polling operations.
225///
226/// Although they are called `Read` and `Write`, this is just a convention, and
227/// the objects can be polled using any set of events.
228#[derive(Debug, Copy, Clone, PartialEq, Eq)]
229pub enum InterestSlot {
230    /// Read interest.
231    Read = 0,
232    /// Write interest.
233    Write = 1,
234}
235
236/// The maximum number of interest slots.
237pub const SLOT_COUNT: usize = 2;
238
239/// A set of poll interests for a single object.
240#[derive(Debug, Default)]
241pub(crate) struct PollInterestSet([PollInterest; SLOT_COUNT]);
242
243impl PollInterestSet {
244    pub fn poll_ready(
245        &mut self,
246        cx: &mut Context<'_>,
247        slot: InterestSlot,
248        events: PollEvents,
249    ) -> Poll<PollEvents> {
250        let interest = &mut self.0[slot as usize];
251        // POLLHUP and POLLERR are always included.
252        let events = events | PollEvents::HUP | PollEvents::ERR;
253        let revents = (interest.observed_revents | interest.delivered_revents) & events;
254        if !revents.is_empty() {
255            interest.events = PollEvents::EMPTY;
256            interest.observed_revents |= revents;
257            interest.delivered_revents &= !revents;
258            Poll::Ready(revents)
259        } else {
260            interest.events = events;
261            if !interest
262                .waker
263                .as_ref()
264                .is_some_and(|w| w.will_wake(cx.waker()))
265            {
266                interest.waker = Some(cx.waker().clone());
267            }
268            Poll::Pending
269        }
270    }
271
272    #[cfg(windows)]
273    pub fn clear_all(&mut self) {
274        *self = Default::default();
275    }
276
277    pub fn clear_ready(&mut self, slot: InterestSlot) {
278        let interest = &mut self.0[slot as usize];
279        interest.events = PollEvents::EMPTY;
280        interest.observed_revents = PollEvents::EMPTY;
281    }
282
283    pub fn events_to_poll(&self) -> PollEvents {
284        self.0.iter().fold(PollEvents::EMPTY, |e, p| {
285            e | if ((p.observed_revents | p.delivered_revents) & p.events).is_empty() {
286                p.events
287            } else {
288                PollEvents::EMPTY
289            }
290        })
291    }
292
293    pub fn wake_ready(&mut self, revents: PollEvents, wakers: &mut WakerList) {
294        wakers.extend(self.0.iter_mut().filter_map(|p| {
295            p.delivered_revents |= revents;
296            if !(p.events & revents).is_empty() {
297                p.waker.take()
298            } else {
299                None
300            }
301        }))
302    }
303}