polling/
lib.rs

1//! Portable interface to epoll, kqueue, event ports, and IOCP.
2//!
3//! Supported platforms:
4//! - [epoll](https://en.wikipedia.org/wiki/Epoll): Linux, Android, RedoxOS
5//! - [kqueue](https://en.wikipedia.org/wiki/Kqueue): macOS, iOS, tvOS, watchOS, visionOS, FreeBSD, NetBSD, OpenBSD,
6//!   DragonFly BSD
7//! - [event ports](https://illumos.org/man/port_create): illumos, Solaris
8//! - [poll](https://en.wikipedia.org/wiki/Poll_(Unix)): VxWorks, Fuchsia, HermitOS, other Unix systems
9//! - [IOCP](https://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports): Windows, Wine (version 7.13+)
10//!
11//! By default, polling is done in oneshot mode, which means interest in I/O events needs to
12//! be re-enabled after an event is delivered if we're interested in the next event of the same
13//! kind. However, level and edge triggered modes are also available for certain operating
14//! systems. See the documentation of the [`PollMode`] type for more information.
15//!
16//! Only one thread can be waiting for I/O events at a time.
17//!
18//! # Examples
19//!
20//! ```no_run
21//! use polling::{Event, Events, Poller};
22//! use std::net::TcpListener;
23//!
24//! // Create a TCP listener.
25//! let socket = TcpListener::bind("127.0.0.1:8000")?;
26//! socket.set_nonblocking(true)?;
27//! let key = 7; // Arbitrary key identifying the socket.
28//!
29//! // Create a poller and register interest in readability on the socket.
30//! let poller = Poller::new()?;
31//! unsafe {
32//!     poller.add(&socket, Event::readable(key))?;
33//! }
34//!
35//! // The event loop.
36//! let mut events = Events::new();
37//! loop {
38//!     // Wait for at least one I/O event.
39//!     events.clear();
40//!     poller.wait(&mut events, None)?;
41//!
42//!     for ev in events.iter() {
43//!         if ev.key == key {
44//!             // Perform a non-blocking accept operation.
45//!             socket.accept()?;
46//!             // Set interest in the next readability event.
47//!             poller.modify(&socket, Event::readable(key))?;
48//!         }
49//!     }
50//! }
51//!
52//! poller.delete(&socket)?;
53//! # std::io::Result::Ok(())
54//! ```
55
56#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
57#![allow(clippy::useless_conversion, clippy::unnecessary_cast, unused_unsafe)]
58#![cfg_attr(docsrs, feature(doc_cfg))]
59#![doc(
60    html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
61)]
62#![doc(
63    html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
64)]
65
66use std::cell::Cell;
67use std::fmt;
68use std::io;
69use std::marker::PhantomData;
70use std::num::NonZeroUsize;
71use std::sync::atomic::{AtomicBool, Ordering};
72use std::sync::Mutex;
73use std::time::{Duration, Instant};
74
75use cfg_if::cfg_if;
76
77cfg_if! {
78    // Note: This cfg is intended to make it easy for polling developers to test
79    // the backend that uses poll, and is not a public API.
80    if #[cfg(polling_test_poll_backend)] {
81        mod poll;
82        use poll as sys;
83    } else if #[cfg(any(
84        target_os = "linux",
85        target_os = "android",
86        target_os = "redox"
87    ))] {
88        mod epoll;
89        use epoll as sys;
90    } else if #[cfg(any(
91        target_os = "illumos",
92        target_os = "solaris",
93    ))] {
94        mod port;
95        use port as sys;
96    } else if #[cfg(any(
97        target_vendor = "apple",
98        target_os = "freebsd",
99        target_os = "netbsd",
100        target_os = "openbsd",
101        target_os = "dragonfly",
102    ))] {
103        mod kqueue;
104        use kqueue as sys;
105    } else if #[cfg(any(
106        target_os = "vxworks",
107        target_os = "hermit",
108        target_os = "fuchsia",
109        target_os = "horizon",
110        unix,
111    ))] {
112        mod poll;
113        use poll as sys;
114    } else if #[cfg(target_os = "windows")] {
115        mod iocp;
116        use iocp as sys;
117    } else {
118        compile_error!("polling does not support this target OS");
119    }
120}
121
122pub mod os;
123
124/// Key associated with notifications.
125const NOTIFY_KEY: usize = usize::MAX;
126
127/// Indicates that a file descriptor or socket can read or write without blocking.
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub struct Event {
130    /// Key identifying the file descriptor or socket.
131    pub key: usize,
132    /// Can it do a read operation without blocking?
133    pub readable: bool,
134    /// Can it do a write operation without blocking?
135    pub writable: bool,
136    /// System-specific event data.
137    extra: sys::EventExtra,
138}
139
140/// The mode in which the poller waits for I/O events.
141#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
142#[non_exhaustive]
143pub enum PollMode {
144    /// Poll in oneshot mode.
145    ///
146    /// In this mode, the poller will only deliver one event per file descriptor or socket.
147    /// Once an event has been delivered, interest in the event needs to be re-enabled
148    /// by calling `Poller::modify` or `Poller::add`.
149    ///
150    /// This is the default mode.
151    Oneshot,
152
153    /// Poll in level-triggered mode.
154    ///
155    /// Once an event has been delivered, polling will continue to deliver that event
156    /// until interest in the event is disabled by calling `Poller::modify` or `Poller::delete`.
157    ///
158    /// Not all operating system support this mode. Trying to register a file descriptor with
159    /// this mode in an unsupported operating system will raise an error. You can check if
160    /// the operating system supports this mode by calling `Poller::supports_level`.
161    Level,
162
163    /// Poll in edge-triggered mode.
164    ///
165    /// Once an event has been delivered, polling will not deliver that event again unless
166    /// a new event occurs.
167    ///
168    /// Not all operating system support this mode. Trying to register a file descriptor with
169    /// this mode in an unsupported operating system will raise an error. You can check if
170    /// the operating system supports this mode by calling `Poller::supports_edge`.
171    Edge,
172
173    /// Poll in both edge-triggered and oneshot mode.
174    ///
175    /// This mode is similar to the `Oneshot` mode, but it will only deliver one event per new
176    /// event.
177    ///
178    /// Not all operating system support this mode. Trying to register a file descriptor with
179    /// this mode in an unsupported operating system will raise an error. You can check if
180    /// the operating system supports this mode by calling `Poller::supports_edge`.
181    EdgeOneshot,
182}
183
184impl Event {
185    /// Create a new event.
186    pub const fn new(key: usize, readable: bool, writable: bool) -> Event {
187        Event {
188            key,
189            readable,
190            writable,
191            extra: sys::EventExtra::empty(),
192        }
193    }
194
195    /// All kinds of events (readable and writable).
196    ///
197    /// Equivalent to: `Event::new(key, true, true)`
198    #[inline]
199    pub const fn all(key: usize) -> Event {
200        Event::new(key, true, true)
201    }
202
203    /// Only the readable event.
204    ///
205    /// Equivalent to: `Event::new(key, true, false)`
206    #[inline]
207    pub const fn readable(key: usize) -> Event {
208        Event::new(key, true, false)
209    }
210
211    /// Only the writable event.
212    ///
213    /// Equivalent to: `Event::new(key, false, true)`
214    #[inline]
215    pub const fn writable(key: usize) -> Event {
216        Event::new(key, false, true)
217    }
218
219    /// No events.
220    ///
221    /// Equivalent to: `Event::new(key, false, false)`
222    #[inline]
223    pub const fn none(key: usize) -> Event {
224        Event::new(key, false, false)
225    }
226
227    /// Add interruption events to this interest.
228    ///
229    /// This usually indicates that the file descriptor or socket has been closed. It corresponds
230    /// to the `EPOLLHUP` and `POLLHUP` events.
231    ///
232    /// Interruption events are only supported on the following platforms:
233    ///
234    /// - `epoll`
235    /// - `poll`
236    /// - IOCP
237    /// - Event Ports
238    ///
239    /// On other platforms, this function is a no-op.
240    #[inline]
241    pub fn set_interrupt(&mut self, active: bool) {
242        self.extra.set_hup(active);
243    }
244
245    /// Add interruption events to this interest.
246    ///
247    /// This usually indicates that the file descriptor or socket has been closed. It corresponds
248    /// to the `EPOLLHUP` and `POLLHUP` events.
249    ///
250    /// Interruption events are only supported on the following platforms:
251    ///
252    /// - `epoll`
253    /// - `poll`
254    /// - IOCP
255    /// - Event Ports
256    ///
257    /// On other platforms, this function is a no-op.
258    #[inline]
259    pub fn with_interrupt(mut self) -> Self {
260        self.set_interrupt(true);
261        self
262    }
263
264    /// Add priority events to this interest.
265    ///
266    /// This indicates that there is urgent data to read. It corresponds to the `EPOLLPRI` and
267    /// `POLLPRI` events.
268    ///
269    /// Priority events are only supported on the following platforms:
270    ///
271    /// - `epoll`
272    /// - `poll`
273    /// - IOCP
274    /// - Event Ports
275    ///
276    /// On other platforms, this function is a no-op.
277    #[inline]
278    pub fn set_priority(&mut self, active: bool) {
279        self.extra.set_pri(active);
280    }
281
282    /// Add priority events to this interest.
283    ///
284    /// This indicates that there is urgent data to read. It corresponds to the `EPOLLPRI` and
285    /// `POLLPRI` events.
286    ///
287    /// Priority events are only supported on the following platforms:
288    ///
289    /// - `epoll`
290    /// - `poll`
291    /// - IOCP
292    /// - Event Ports
293    ///
294    /// On other platforms, this function is a no-op.
295    #[inline]
296    pub fn with_priority(mut self) -> Self {
297        self.set_priority(true);
298        self
299    }
300
301    /// Tell if this event is the result of an interrupt notification.
302    ///
303    /// This usually indicates that the file descriptor or socket has been closed. It corresponds
304    /// to the `EPOLLHUP` and `POLLHUP` events.
305    ///
306    /// Interruption events are only supported on the following platforms:
307    ///
308    /// - `epoll`
309    /// - `poll`
310    /// - IOCP
311    /// - Event Ports
312    ///
313    /// On other platforms, this always returns `false`.
314    #[inline]
315    pub fn is_interrupt(&self) -> bool {
316        self.extra.is_hup()
317    }
318
319    /// Tell if this event is the result of a priority notification.
320    ///
321    /// This indicates that there is urgent data to read. It corresponds to the `EPOLLPRI` and
322    /// `POLLPRI` events.
323    ///
324    /// Priority events are only supported on the following platforms:
325    ///
326    /// - `epoll`
327    /// - `poll`
328    /// - IOCP
329    /// - Event Ports
330    ///
331    /// On other platforms, this always returns `false`.
332    #[inline]
333    pub fn is_priority(&self) -> bool {
334        self.extra.is_pri()
335    }
336
337    /// Tells if this event is the result of a connection failure.
338    ///
339    /// This function checks if a TCP connection has failed. It corresponds to the `EPOLLERR`  or `EPOLLHUP` event in Linux
340    /// and `CONNECT_FAILED` event in Windows IOCP.
341    ///
342    /// # Examples
343    ///
344    /// ```
345    /// use std::{io, net};
346    /// // Assuming polling and socket2 are included as dependencies in Cargo.toml
347    /// use polling::Event;
348    /// use socket2::Type;
349    ///
350    /// fn main() -> io::Result<()> {
351    ///     let socket = socket2::Socket::new(socket2::Domain::IPV4, Type::STREAM, None)?;
352    ///     let poller = polling::Poller::new()?;
353    ///     unsafe {
354    ///         poller.add(&socket, Event::new(0, true, true))?;
355    ///     }
356    ///     let addr = net::SocketAddr::new(net::Ipv4Addr::LOCALHOST.into(), 8080);
357    ///     socket.set_nonblocking(true)?;
358    ///     let _ = socket.connect(&addr.into());
359    ///
360    ///     let mut events = polling::Events::new();
361    ///
362    ///     events.clear();
363    ///     poller.wait(&mut events, None)?;
364    ///
365    ///     let event = events.iter().next();
366    ///
367    ///     let event = match event {
368    ///         Some(event) => event,
369    ///         None => {
370    ///             println!("no event");
371    ///             return Ok(());
372    ///         },
373    ///     };
374    ///
375    ///     println!("event: {:?}", event);
376    ///     if event
377    ///         .is_connect_failed()
378    ///         .unwrap_or_default()
379    ///     {
380    ///         println!("connect failed");
381    ///     }
382    ///
383    ///     Ok(())
384    /// }
385    /// ```
386    ///
387    /// # Returns
388    ///
389    /// Returns `Some(true)` if the connection has failed, `Some(false)` if the connection has not failed,
390    /// or `None` if the platform does not support detecting this condition.
391    #[inline]
392    #[deprecated(
393        since = "3.4.0",
394        note = "use `is_err` in combination of is_hup instead, see documentation for `is_err`"
395    )]
396    pub fn is_connect_failed(&self) -> Option<bool> {
397        self.extra.is_connect_failed()
398    }
399
400    /// Tells if this event is the result of a connection failure.
401    ///
402    /// This function checks if an error exist, particularly useful in detecting if TCP connection failed. It corresponds to the `EPOLLERR` event in Linux
403    /// and `CONNECT_FAILED` event in Windows IOCP.
404    ///
405    /// ## Caveats
406    ///
407    /// In `epoll`, a TCP connection failure is indicated by `EPOLLERR` + `EPOLLHUP`, though just `EPOLLERR` is enough to indicate a connection failure.
408    /// EPOLLHUP may happen when we haven't event called `connect` on the socket, but it is still a valid event to check for.
409    ///
410    /// Returns `Some(true)` if the connection has failed, `Some(false)` if there is no error,
411    /// or `None` if the platform does not support detecting this condition.
412    #[inline]
413    pub fn is_err(&self) -> Option<bool> {
414        self.extra.is_err()
415    }
416
417    /// Remove any extra information from this event.
418    #[inline]
419    pub fn clear_extra(&mut self) {
420        self.extra = sys::EventExtra::empty();
421    }
422
423    /// Get a version of this event with no extra information.
424    ///
425    /// This is useful for comparing events with `==`.
426    #[inline]
427    pub fn with_no_extra(mut self) -> Self {
428        self.clear_extra();
429        self
430    }
431}
432
433/// Waits for I/O events.
434pub struct Poller {
435    poller: sys::Poller,
436    lock: Mutex<()>,
437    notified: AtomicBool,
438}
439
440impl Poller {
441    /// Creates a new poller.
442    ///
443    /// # Examples
444    ///
445    /// ```
446    /// use polling::Poller;
447    ///
448    /// let poller = Poller::new()?;
449    /// # std::io::Result::Ok(())
450    /// ```
451    pub fn new() -> io::Result<Poller> {
452        Ok(Poller {
453            poller: sys::Poller::new()?,
454            lock: Mutex::new(()),
455            notified: AtomicBool::new(false),
456        })
457    }
458
459    /// Tell whether or not this `Poller` supports level-triggered polling.
460    pub fn supports_level(&self) -> bool {
461        self.poller.supports_level()
462    }
463
464    /// Tell whether or not this `Poller` supports edge-triggered polling.
465    pub fn supports_edge(&self) -> bool {
466        self.poller.supports_edge()
467    }
468
469    /// Adds a file descriptor or socket to the poller.
470    ///
471    /// A file descriptor or socket is considered readable or writable when a read or write
472    /// operation on it would not block. This doesn't mean the read or write operation will
473    /// succeed, it only means the operation will return immediately.
474    ///
475    /// If interest is set in both readability and writability, the two kinds of events might be
476    /// delivered either separately or together.
477    ///
478    /// For example, interest in `Event { key: 7, readable: true, writable: true }` might result in
479    /// a single [`Event`] of the same form, or in two separate [`Event`]s:
480    /// - `Event { key: 7, readable: true, writable: false }`
481    /// - `Event { key: 7, readable: false, writable: true }`
482    ///
483    /// Note that interest in I/O events needs to be re-enabled using
484    /// [`modify()`][`Poller::modify()`] again after an event is delivered if we're interested in
485    /// the next event of the same kind.
486    ///
487    /// It is possible to register interest in the same file descriptor or socket using multiple
488    /// separate [`Poller`] instances. When the event is delivered, one or more [`Poller`]s are
489    /// notified with that event. The exact number of [`Poller`]s notified depends on the
490    /// underlying platform. When registering multiple sources into one event, the user should
491    /// be careful to accommodate for events lost to other pollers.
492    ///
493    /// One may also register one source into other, non-`polling` event loops, like GLib's
494    /// context. While the plumbing will vary from platform to platform, in general the [`Poller`]
495    /// will act as if the source was registered with another [`Poller`], with the same caveats
496    /// as above.
497    ///
498    /// # Safety
499    ///
500    /// The source must be [`delete()`]d from this `Poller` before it is dropped.
501    ///
502    /// [`delete()`]: Poller::delete
503    ///
504    /// # Errors
505    ///
506    /// This method returns an error in the following situations:
507    ///
508    /// * If `key` equals `usize::MAX` because that key is reserved for internal use.
509    /// * If an error is returned by the syscall.
510    ///
511    /// # Examples
512    ///
513    /// Set interest in all events:
514    ///
515    /// ```no_run
516    /// use polling::{Event, Poller};
517    ///
518    /// let source = std::net::TcpListener::bind("127.0.0.1:0")?;
519    /// source.set_nonblocking(true)?;
520    /// let key = 7;
521    ///
522    /// let poller = Poller::new()?;
523    /// unsafe {
524    ///     poller.add(&source, Event::all(key))?;
525    /// }
526    /// poller.delete(&source)?;
527    /// # std::io::Result::Ok(())
528    /// ```
529    pub unsafe fn add(&self, source: impl AsRawSource, interest: Event) -> io::Result<()> {
530        self.add_with_mode(source, interest, PollMode::Oneshot)
531    }
532
533    /// Adds a file descriptor or socket to the poller in the specified mode.
534    ///
535    /// This is identical to the `add()` function, but allows specifying the
536    /// polling mode to use for this socket.
537    ///
538    /// # Safety
539    ///
540    /// The source must be [`delete()`]d from this `Poller` before it is dropped.
541    ///
542    /// [`delete()`]: Poller::delete
543    ///
544    /// # Errors
545    ///
546    /// If the operating system does not support the specified mode, this function
547    /// will return an error.
548    pub unsafe fn add_with_mode(
549        &self,
550        source: impl AsRawSource,
551        interest: Event,
552        mode: PollMode,
553    ) -> io::Result<()> {
554        if interest.key == NOTIFY_KEY {
555            return Err(io::Error::new(
556                io::ErrorKind::InvalidInput,
557                "the key is not allowed to be `usize::MAX`",
558            ));
559        }
560        self.poller.add(source.raw(), interest, mode)
561    }
562
563    /// Modifies the interest in a file descriptor or socket.
564    ///
565    /// This method has the same behavior as [`add()`][`Poller::add()`] except it modifies the
566    /// interest of a previously added file descriptor or socket.
567    ///
568    /// To use this method with a file descriptor or socket, you must first add it using
569    /// [`add()`][`Poller::add()`].
570    ///
571    /// Note that interest in I/O events needs to be re-enabled using
572    /// [`modify()`][`Poller::modify()`] again after an event is delivered if we're interested in
573    /// the next event of the same kind.
574    ///
575    /// # Errors
576    ///
577    /// This method returns an error in the following situations:
578    ///
579    /// * If `key` equals `usize::MAX` because that key is reserved for internal use.
580    /// * If an error is returned by the syscall.
581    ///
582    /// # Examples
583    ///
584    /// To enable interest in all events:
585    ///
586    /// ```no_run
587    /// # use polling::{Event, Poller};
588    /// # let source = std::net::TcpListener::bind("127.0.0.1:0")?;
589    /// # let key = 7;
590    /// # let poller = Poller::new()?;
591    /// # unsafe { poller.add(&source, Event::none(key))?; }
592    /// poller.modify(&source, Event::all(key))?;
593    /// # std::io::Result::Ok(())
594    /// ```
595    ///
596    /// To enable interest in readable events and disable interest in writable events:
597    ///
598    /// ```no_run
599    /// # use polling::{Event, Poller};
600    /// # let source = std::net::TcpListener::bind("127.0.0.1:0")?;
601    /// # let key = 7;
602    /// # let poller = Poller::new()?;
603    /// # unsafe { poller.add(&source, Event::none(key))?; }
604    /// poller.modify(&source, Event::readable(key))?;
605    /// # poller.delete(&source)?;
606    /// # std::io::Result::Ok(())
607    /// ```
608    ///
609    /// To disable interest in readable events and enable interest in writable events:
610    ///
611    /// ```no_run
612    /// # use polling::{Event, Poller};
613    /// # let poller = Poller::new()?;
614    /// # let key = 7;
615    /// # let source = std::net::TcpListener::bind("127.0.0.1:0")?;
616    /// # unsafe { poller.add(&source, Event::none(key))? };
617    /// poller.modify(&source, Event::writable(key))?;
618    /// # poller.delete(&source)?;
619    /// # std::io::Result::Ok(())
620    /// ```
621    ///
622    /// To disable interest in all events:
623    ///
624    /// ```no_run
625    /// # use polling::{Event, Poller};
626    /// # let source = std::net::TcpListener::bind("127.0.0.1:0")?;
627    /// # let key = 7;
628    /// # let poller = Poller::new()?;
629    /// # unsafe { poller.add(&source, Event::none(key))?; }
630    /// poller.modify(&source, Event::none(key))?;
631    /// # poller.delete(&source)?;
632    /// # std::io::Result::Ok(())
633    /// ```
634    pub fn modify(&self, source: impl AsSource, interest: Event) -> io::Result<()> {
635        self.modify_with_mode(source, interest, PollMode::Oneshot)
636    }
637
638    /// Modifies interest in a file descriptor or socket to the poller, but with the specified
639    /// mode.
640    ///
641    /// This is identical to the `modify()` function, but allows specifying the polling mode
642    /// to use for this socket.
643    ///
644    /// # Performance Notes
645    ///
646    /// This function can be used to change a source from one polling mode to another. However,
647    /// on some platforms, this switch can cause delays in the delivery of events.
648    ///
649    /// # Errors
650    ///
651    /// If the operating system does not support the specified mode, this function will return
652    /// an error.
653    pub fn modify_with_mode(
654        &self,
655        source: impl AsSource,
656        interest: Event,
657        mode: PollMode,
658    ) -> io::Result<()> {
659        if interest.key == NOTIFY_KEY {
660            return Err(io::Error::new(
661                io::ErrorKind::InvalidInput,
662                "the key is not allowed to be `usize::MAX`",
663            ));
664        }
665        self.poller.modify(source.source(), interest, mode)
666    }
667
668    /// Removes a file descriptor or socket from the poller.
669    ///
670    /// Unlike [`add()`][`Poller::add()`], this method only removes the file descriptor or
671    /// socket from the poller without putting it back into blocking mode.
672    ///
673    /// # Examples
674    ///
675    /// ```
676    /// use polling::{Event, Poller};
677    /// use std::net::TcpListener;
678    ///
679    /// let socket = TcpListener::bind("127.0.0.1:0")?;
680    /// socket.set_nonblocking(true)?;
681    /// let key = 7;
682    ///
683    /// let poller = Poller::new()?;
684    /// unsafe { poller.add(&socket, Event::all(key))?; }
685    /// poller.delete(&socket)?;
686    /// # std::io::Result::Ok(())
687    /// ```
688    pub fn delete(&self, source: impl AsSource) -> io::Result<()> {
689        self.poller.delete(source.source())
690    }
691
692    /// Waits for at least one I/O event and returns the number of new events.
693    ///
694    /// New events will be appended to `events`. If necessary, make sure to clear the
695    /// [`Events`][Events::clear()] before calling [`wait()`][`Poller::wait()`]!
696    ///
697    /// This method will return with no new events if a notification is delivered by the
698    /// [`notify()`] method, or the timeout is reached. Sometimes it may even return with no events
699    /// spuriously.
700    ///
701    /// Only one thread can wait on I/O. If another thread is already in [`wait()`], concurrent
702    /// calls to this method will return immediately with no new events.
703    ///
704    /// If the operating system is ready to deliver a large number of events at once, this method
705    /// may decide to deliver them in smaller batches.
706    ///
707    /// [`notify()`]: `Poller::notify()`
708    /// [`wait()`]: `Poller::wait()`
709    ///
710    /// # Examples
711    ///
712    /// ```
713    /// use polling::{Event, Events, Poller};
714    /// use std::net::TcpListener;
715    /// use std::time::Duration;
716    ///
717    /// let socket = TcpListener::bind("127.0.0.1:0")?;
718    /// socket.set_nonblocking(true)?;
719    /// let key = 7;
720    ///
721    /// let poller = Poller::new()?;
722    /// unsafe {
723    ///     poller.add(&socket, Event::all(key))?;
724    /// }
725    ///
726    /// let mut events = Events::new();
727    /// let n = poller.wait(&mut events, Some(Duration::from_secs(1)))?;
728    /// poller.delete(&socket)?;
729    /// # std::io::Result::Ok(())
730    /// ```
731    pub fn wait(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
732        let span = tracing::trace_span!("Poller::wait", ?timeout);
733        let _enter = span.enter();
734
735        if let Ok(_lock) = self.lock.try_lock() {
736            let deadline = timeout.and_then(|timeout| Instant::now().checked_add(timeout));
737
738            loop {
739                // Figure out how long to wait for.
740                let timeout =
741                    deadline.map(|deadline| deadline.saturating_duration_since(Instant::now()));
742
743                // Wait for I/O events.
744                if let Err(e) = self.poller.wait(&mut events.events, timeout) {
745                    // If the wait was interrupted by a signal, clear events and try again.
746                    if e.kind() == io::ErrorKind::Interrupted {
747                        events.clear();
748                        continue;
749                    } else {
750                        return Err(e);
751                    }
752                }
753
754                // Clear the notification, if any.
755                self.notified.swap(false, Ordering::SeqCst);
756
757                // Indicate number of events.
758                return Ok(events.len());
759            }
760        } else {
761            tracing::trace!("wait: skipping because another thread is already waiting on I/O");
762            Ok(0)
763        }
764    }
765
766    /// Wakes up the current or the following invocation of [`wait()`].
767    ///
768    /// If no thread is calling [`wait()`] right now, this method will cause the following call
769    /// to wake up immediately.
770    ///
771    /// [`wait()`]: `Poller::wait()`
772    ///
773    /// # Examples
774    ///
775    /// ```
776    /// use polling::{Events, Poller};
777    ///
778    /// let poller = Poller::new()?;
779    ///
780    /// // Notify the poller.
781    /// poller.notify()?;
782    ///
783    /// let mut events = Events::new();
784    /// poller.wait(&mut events, None)?; // wakes up immediately
785    /// assert!(events.is_empty());
786    /// # std::io::Result::Ok(())
787    /// ```
788    pub fn notify(&self) -> io::Result<()> {
789        let span = tracing::trace_span!("Poller::notify");
790        let _enter = span.enter();
791
792        if self
793            .notified
794            .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
795            .is_ok()
796        {
797            self.poller.notify()?;
798        }
799        Ok(())
800    }
801}
802
803/// A container for I/O events.
804pub struct Events {
805    events: sys::Events,
806
807    /// This is intended to be used from &mut, thread locally, so we should make it !Sync
808    /// for consistency with the rest of the API.
809    _not_sync: PhantomData<Cell<()>>,
810}
811
812impl Default for Events {
813    #[inline]
814    fn default() -> Self {
815        Self::new()
816    }
817}
818
819impl Events {
820    /// Create a new container for events, using the default capacity.
821    ///
822    /// The default capacity is 1024.
823    ///
824    /// # Examples
825    ///
826    /// ```
827    /// use polling::Events;
828    ///
829    /// let events = Events::new();
830    /// ```
831    #[inline]
832    pub fn new() -> Self {
833        // ESP-IDF has a low amount of RAM, so we use a smaller default capacity.
834        #[cfg(target_os = "espidf")]
835        const DEFAULT_CAPACITY: usize = 32;
836
837        #[cfg(not(target_os = "espidf"))]
838        const DEFAULT_CAPACITY: usize = 1024;
839
840        Self::with_capacity(NonZeroUsize::new(DEFAULT_CAPACITY).unwrap())
841    }
842
843    /// Create a new container with the provided capacity.
844    ///
845    /// # Examples
846    ///
847    /// ```
848    /// use polling::Events;
849    /// use std::num::NonZeroUsize;
850    ///
851    /// let capacity = NonZeroUsize::new(1024).unwrap();
852    /// let events = Events::with_capacity(capacity);
853    /// ```
854    #[inline]
855    pub fn with_capacity(capacity: NonZeroUsize) -> Self {
856        Self {
857            events: sys::Events::with_capacity(capacity.get()),
858            _not_sync: PhantomData,
859        }
860    }
861
862    /// Create a new iterator over I/O events.
863    ///
864    /// This returns all of the events in the container, excluding the notification event.
865    ///
866    /// # Examples
867    ///
868    /// ```
869    /// use polling::{Event, Events, Poller};
870    /// use std::time::Duration;
871    ///
872    /// # fn main() -> std::io::Result<()> {
873    /// let poller = Poller::new()?;
874    /// let mut events = Events::new();
875    ///
876    /// poller.wait(&mut events, Some(Duration::from_secs(0)))?;
877    /// assert!(events.iter().next().is_none());
878    /// # Ok(()) }
879    /// ```
880    #[inline]
881    pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
882        self.events.iter().filter(|ev| ev.key != NOTIFY_KEY)
883    }
884
885    /// Delete all of the events in the container.
886    ///
887    /// # Examples
888    ///
889    /// ```no_run
890    /// use polling::{Event, Events, Poller};
891    ///
892    /// # fn main() -> std::io::Result<()> {
893    /// let poller = Poller::new()?;
894    /// let mut events = Events::new();
895    ///
896    /// /* register some sources */
897    ///
898    /// poller.wait(&mut events, None)?;
899    ///
900    /// events.clear();
901    /// # Ok(()) }
902    /// ```
903    #[inline]
904    pub fn clear(&mut self) {
905        self.events.clear();
906    }
907
908    /// Returns the number of events in the container.
909    ///
910    /// # Examples
911    ///
912    /// ```
913    /// use polling::Events;
914    ///
915    /// let events = Events::new();
916    /// assert_eq!(events.len(), 0);
917    /// ```
918    #[inline]
919    pub fn len(&self) -> usize {
920        self.iter().count()
921    }
922
923    /// Returns `true` if the container contains no events.
924    ///
925    /// # Examples
926    ///
927    /// ```
928    /// use polling::Events;
929    ///
930    /// let events = Events::new();
931    /// assert!(events.is_empty());
932    /// ```
933    #[inline]
934    pub fn is_empty(&self) -> bool {
935        self.len() == 0
936    }
937
938    /// Get the total capacity of the list.
939    ///
940    /// # Examples
941    ///
942    /// ```
943    /// use polling::Events;
944    /// use std::num::NonZeroUsize;
945    ///
946    /// let cap = NonZeroUsize::new(10).unwrap();
947    /// let events = Events::with_capacity(std::num::NonZeroUsize::new(10).unwrap());
948    /// assert_eq!(events.capacity(), cap);
949    /// ```
950    #[inline]
951    pub fn capacity(&self) -> NonZeroUsize {
952        NonZeroUsize::new(self.events.capacity()).unwrap()
953    }
954}
955
956impl fmt::Debug for Events {
957    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
958        f.write_str("Events { .. }")
959    }
960}
961
962#[cfg(all(
963    any(
964        target_os = "linux",
965        target_os = "android",
966        target_os = "illumos",
967        target_os = "solaris",
968        target_vendor = "apple",
969        target_os = "freebsd",
970        target_os = "netbsd",
971        target_os = "openbsd",
972        target_os = "dragonfly",
973    ),
974    not(polling_test_poll_backend),
975))]
976#[cfg_attr(
977    docsrs,
978    doc(cfg(any(
979        target_os = "linux",
980        target_os = "android",
981        target_os = "illumos",
982        target_os = "solaris",
983        target_vendor = "apple",
984        target_os = "freebsd",
985        target_os = "netbsd",
986        target_os = "openbsd",
987        target_os = "dragonfly",
988    )))
989)]
990mod raw_fd_impl {
991    use crate::Poller;
992    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
993
994    impl AsRawFd for Poller {
995        fn as_raw_fd(&self) -> RawFd {
996            self.poller.as_raw_fd()
997        }
998    }
999
1000    impl AsFd for Poller {
1001        fn as_fd(&self) -> BorrowedFd<'_> {
1002            self.poller.as_fd()
1003        }
1004    }
1005}
1006
1007#[cfg(windows)]
1008#[cfg_attr(docsrs, doc(cfg(windows)))]
1009mod raw_handle_impl {
1010    use crate::Poller;
1011    use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, RawHandle};
1012
1013    impl AsRawHandle for Poller {
1014        fn as_raw_handle(&self) -> RawHandle {
1015            self.poller.as_raw_handle()
1016        }
1017    }
1018
1019    impl AsHandle for Poller {
1020        fn as_handle(&self) -> BorrowedHandle<'_> {
1021            self.poller.as_handle()
1022        }
1023    }
1024}
1025
1026impl fmt::Debug for Poller {
1027    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1028        self.poller.fmt(f)
1029    }
1030}
1031
1032cfg_if! {
1033    if #[cfg(any(unix, target_os = "hermit"))] {
1034        #[cfg(unix)]
1035        use std::os::unix::io::{AsRawFd, RawFd, AsFd, BorrowedFd};
1036        #[cfg(target_os = "hermit")]
1037        use std::os::hermit::io::{AsRawFd, RawFd, AsFd, BorrowedFd};
1038
1039        /// A resource with a raw file descriptor.
1040        pub trait AsRawSource {
1041            /// Returns the raw file descriptor.
1042            fn raw(&self) -> RawFd;
1043        }
1044
1045        impl<T: AsRawFd> AsRawSource for &T {
1046            fn raw(&self) -> RawFd {
1047                self.as_raw_fd()
1048            }
1049        }
1050
1051        impl AsRawSource for RawFd {
1052            fn raw(&self) -> RawFd {
1053                *self
1054            }
1055        }
1056
1057        /// A resource with a borrowed file descriptor.
1058        pub trait AsSource: AsFd {
1059            /// Returns the borrowed file descriptor.
1060            fn source(&self) -> BorrowedFd<'_> {
1061                self.as_fd()
1062            }
1063        }
1064
1065        impl<T: AsFd> AsSource for T {}
1066    } else if #[cfg(windows)] {
1067        use std::os::windows::io::{AsRawSocket, RawSocket, AsSocket, BorrowedSocket};
1068
1069        /// A resource with a raw socket.
1070        pub trait AsRawSource {
1071            /// Returns the raw socket.
1072            fn raw(&self) -> RawSocket;
1073        }
1074
1075        impl<T: AsRawSocket> AsRawSource for &T {
1076            fn raw(&self) -> RawSocket {
1077                self.as_raw_socket()
1078            }
1079        }
1080
1081        impl AsRawSource for RawSocket {
1082            fn raw(&self) -> RawSocket {
1083                *self
1084            }
1085        }
1086
1087        /// A resource with a borrowed socket.
1088        pub trait AsSource: AsSocket {
1089            /// Returns the borrowed socket.
1090            fn source(&self) -> BorrowedSocket<'_> {
1091                self.as_socket()
1092            }
1093        }
1094
1095        impl<T: AsSocket> AsSource for T {}
1096    }
1097}
1098
1099#[allow(unused)]
1100fn unsupported_error(err: impl Into<String>) -> io::Error {
1101    io::Error::new(io::ErrorKind::Unsupported, err.into())
1102}
1103
1104fn _assert_send_and_sync() {
1105    fn assert_send<T: Send>() {}
1106    fn assert_sync<T: Sync>() {}
1107
1108    assert_send::<Poller>();
1109    assert_sync::<Poller>();
1110
1111    assert_send::<Event>();
1112    assert_sync::<Event>();
1113
1114    assert_send::<Events>();
1115    // Events can be !Sync
1116}