Skip to main content

polling/
lib.rs

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