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        #[cfg(feature = "tracing")]
733        let span = tracing::trace_span!("Poller::wait", ?timeout);
734        #[cfg(feature = "tracing")]
735        let _enter = span.enter();
736
737        if let Ok(_lock) = self.lock.try_lock() {
738            let deadline = timeout.and_then(|timeout| Instant::now().checked_add(timeout));
739
740            loop {
741                // Figure out how long to wait for.
742                let timeout =
743                    deadline.map(|deadline| deadline.saturating_duration_since(Instant::now()));
744
745                // Wait for I/O events.
746                if let Err(e) = self.poller.wait(&mut events.events, timeout) {
747                    // If the wait was interrupted by a signal, clear events and try again.
748                    if e.kind() == io::ErrorKind::Interrupted {
749                        events.clear();
750                        continue;
751                    } else {
752                        return Err(e);
753                    }
754                }
755
756                // Clear the notification, if any.
757                self.notified.swap(false, Ordering::SeqCst);
758
759                // Indicate number of events.
760                return Ok(events.len());
761            }
762        } else {
763            #[cfg(feature = "tracing")]
764            tracing::trace!("wait: skipping because another thread is already waiting on I/O");
765            Ok(0)
766        }
767    }
768
769    /// Wakes up the current or the following invocation of [`wait()`].
770    ///
771    /// If no thread is calling [`wait()`] right now, this method will cause the following call
772    /// to wake up immediately.
773    ///
774    /// [`wait()`]: `Poller::wait()`
775    ///
776    /// # Examples
777    ///
778    /// ```
779    /// use polling::{Events, Poller};
780    ///
781    /// let poller = Poller::new()?;
782    ///
783    /// // Notify the poller.
784    /// poller.notify()?;
785    ///
786    /// let mut events = Events::new();
787    /// poller.wait(&mut events, None)?; // wakes up immediately
788    /// assert!(events.is_empty());
789    /// # std::io::Result::Ok(())
790    /// ```
791    pub fn notify(&self) -> io::Result<()> {
792        #[cfg(feature = "tracing")]
793        let span = tracing::trace_span!("Poller::notify");
794        #[cfg(feature = "tracing")]
795        let _enter = span.enter();
796
797        if self
798            .notified
799            .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
800            .is_ok()
801        {
802            self.poller.notify()?;
803        }
804        Ok(())
805    }
806}
807
808/// A container for I/O events.
809pub struct Events {
810    events: sys::Events,
811
812    /// This is intended to be used from &mut, thread locally, so we should make it !Sync
813    /// for consistency with the rest of the API.
814    _not_sync: PhantomData<Cell<()>>,
815}
816
817impl Default for Events {
818    #[inline]
819    fn default() -> Self {
820        Self::new()
821    }
822}
823
824impl Events {
825    /// Create a new container for events, using the default capacity.
826    ///
827    /// The default capacity is 1024.
828    ///
829    /// # Examples
830    ///
831    /// ```
832    /// use polling::Events;
833    ///
834    /// let events = Events::new();
835    /// ```
836    #[inline]
837    pub fn new() -> Self {
838        // ESP-IDF has a low amount of RAM, so we use a smaller default capacity.
839        #[cfg(target_os = "espidf")]
840        const DEFAULT_CAPACITY: usize = 32;
841
842        #[cfg(not(target_os = "espidf"))]
843        const DEFAULT_CAPACITY: usize = 1024;
844
845        Self::with_capacity(NonZeroUsize::new(DEFAULT_CAPACITY).unwrap())
846    }
847
848    /// Create a new container with the provided capacity.
849    ///
850    /// # Examples
851    ///
852    /// ```
853    /// use polling::Events;
854    /// use std::num::NonZeroUsize;
855    ///
856    /// let capacity = NonZeroUsize::new(1024).unwrap();
857    /// let events = Events::with_capacity(capacity);
858    /// ```
859    #[inline]
860    pub fn with_capacity(capacity: NonZeroUsize) -> Self {
861        Self {
862            events: sys::Events::with_capacity(capacity.get()),
863            _not_sync: PhantomData,
864        }
865    }
866
867    /// Create a new iterator over I/O events.
868    ///
869    /// This returns all of the events in the container, excluding the notification event.
870    ///
871    /// # Examples
872    ///
873    /// ```
874    /// use polling::{Event, Events, Poller};
875    /// use std::time::Duration;
876    ///
877    /// # fn main() -> std::io::Result<()> {
878    /// let poller = Poller::new()?;
879    /// let mut events = Events::new();
880    ///
881    /// poller.wait(&mut events, Some(Duration::from_secs(0)))?;
882    /// assert!(events.iter().next().is_none());
883    /// # Ok(()) }
884    /// ```
885    #[inline]
886    pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
887        self.events.iter().filter(|ev| ev.key != NOTIFY_KEY)
888    }
889
890    /// Delete all of the events in the container.
891    ///
892    /// # Examples
893    ///
894    /// ```no_run
895    /// use polling::{Event, Events, Poller};
896    ///
897    /// # fn main() -> std::io::Result<()> {
898    /// let poller = Poller::new()?;
899    /// let mut events = Events::new();
900    ///
901    /// /* register some sources */
902    ///
903    /// poller.wait(&mut events, None)?;
904    ///
905    /// events.clear();
906    /// # Ok(()) }
907    /// ```
908    #[inline]
909    pub fn clear(&mut self) {
910        self.events.clear();
911    }
912
913    /// Returns the number of events in the container.
914    ///
915    /// # Examples
916    ///
917    /// ```
918    /// use polling::Events;
919    ///
920    /// let events = Events::new();
921    /// assert_eq!(events.len(), 0);
922    /// ```
923    #[inline]
924    pub fn len(&self) -> usize {
925        self.iter().count()
926    }
927
928    /// Returns `true` if the container contains no events.
929    ///
930    /// # Examples
931    ///
932    /// ```
933    /// use polling::Events;
934    ///
935    /// let events = Events::new();
936    /// assert!(events.is_empty());
937    /// ```
938    #[inline]
939    pub fn is_empty(&self) -> bool {
940        self.len() == 0
941    }
942
943    /// Get the total capacity of the list.
944    ///
945    /// # Examples
946    ///
947    /// ```
948    /// use polling::Events;
949    /// use std::num::NonZeroUsize;
950    ///
951    /// let cap = NonZeroUsize::new(10).unwrap();
952    /// let events = Events::with_capacity(std::num::NonZeroUsize::new(10).unwrap());
953    /// assert_eq!(events.capacity(), cap);
954    /// ```
955    #[inline]
956    pub fn capacity(&self) -> NonZeroUsize {
957        NonZeroUsize::new(self.events.capacity()).unwrap()
958    }
959}
960
961impl fmt::Debug for Events {
962    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963        f.write_str("Events { .. }")
964    }
965}
966
967#[cfg(all(
968    any(
969        target_os = "linux",
970        target_os = "android",
971        target_os = "redox",
972        target_os = "illumos",
973        target_os = "solaris",
974        target_vendor = "apple",
975        target_os = "freebsd",
976        target_os = "netbsd",
977        target_os = "openbsd",
978        target_os = "dragonfly",
979    ),
980    not(polling_test_poll_backend),
981))]
982#[cfg_attr(
983    docsrs,
984    doc(cfg(any(
985        target_os = "linux",
986        target_os = "android",
987        target_os = "redox",
988        target_os = "illumos",
989        target_os = "solaris",
990        target_vendor = "apple",
991        target_os = "freebsd",
992        target_os = "netbsd",
993        target_os = "openbsd",
994        target_os = "dragonfly",
995    )))
996)]
997mod raw_fd_impl {
998    use crate::Poller;
999    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
1000
1001    impl AsRawFd for Poller {
1002        fn as_raw_fd(&self) -> RawFd {
1003            self.poller.as_raw_fd()
1004        }
1005    }
1006
1007    impl AsFd for Poller {
1008        fn as_fd(&self) -> BorrowedFd<'_> {
1009            self.poller.as_fd()
1010        }
1011    }
1012}
1013
1014#[cfg(windows)]
1015#[cfg_attr(docsrs, doc(cfg(windows)))]
1016mod raw_handle_impl {
1017    use crate::Poller;
1018    use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, RawHandle};
1019
1020    impl AsRawHandle for Poller {
1021        fn as_raw_handle(&self) -> RawHandle {
1022            self.poller.as_raw_handle()
1023        }
1024    }
1025
1026    impl AsHandle for Poller {
1027        fn as_handle(&self) -> BorrowedHandle<'_> {
1028            self.poller.as_handle()
1029        }
1030    }
1031}
1032
1033impl fmt::Debug for Poller {
1034    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1035        self.poller.fmt(f)
1036    }
1037}
1038
1039cfg_if! {
1040    if #[cfg(any(unix, target_os = "hermit"))] {
1041        #[cfg(unix)]
1042        use std::os::unix::io::{AsRawFd, RawFd, AsFd, BorrowedFd};
1043        #[cfg(target_os = "hermit")]
1044        use std::os::hermit::io::{AsRawFd, RawFd, AsFd, BorrowedFd};
1045
1046        /// A resource with a raw file descriptor.
1047        pub trait AsRawSource {
1048            /// Returns the raw file descriptor.
1049            fn raw(&self) -> RawFd;
1050        }
1051
1052        impl<T: AsRawFd> AsRawSource for &T {
1053            fn raw(&self) -> RawFd {
1054                self.as_raw_fd()
1055            }
1056        }
1057
1058        impl AsRawSource for RawFd {
1059            fn raw(&self) -> RawFd {
1060                *self
1061            }
1062        }
1063
1064        /// A resource with a borrowed file descriptor.
1065        pub trait AsSource: AsFd {
1066            /// Returns the borrowed file descriptor.
1067            fn source(&self) -> BorrowedFd<'_> {
1068                self.as_fd()
1069            }
1070        }
1071
1072        impl<T: AsFd> AsSource for T {}
1073    } else if #[cfg(windows)] {
1074        use std::os::windows::io::{AsRawSocket, RawSocket, AsSocket, BorrowedSocket};
1075
1076        /// A resource with a raw socket.
1077        pub trait AsRawSource {
1078            /// Returns the raw socket.
1079            fn raw(&self) -> RawSocket;
1080        }
1081
1082        impl<T: AsRawSocket> AsRawSource for &T {
1083            fn raw(&self) -> RawSocket {
1084                self.as_raw_socket()
1085            }
1086        }
1087
1088        impl AsRawSource for RawSocket {
1089            fn raw(&self) -> RawSocket {
1090                *self
1091            }
1092        }
1093
1094        /// A resource with a borrowed socket.
1095        pub trait AsSource: AsSocket {
1096            /// Returns the borrowed socket.
1097            fn source(&self) -> BorrowedSocket<'_> {
1098                self.as_socket()
1099            }
1100        }
1101
1102        impl<T: AsSocket> AsSource for T {}
1103    }
1104}
1105
1106#[allow(unused)]
1107fn unsupported_error(err: impl Into<String>) -> io::Error {
1108    io::Error::new(io::ErrorKind::Unsupported, err.into())
1109}
1110
1111fn _assert_send_and_sync() {
1112    fn assert_send<T: Send>() {}
1113    fn assert_sync<T: Sync>() {}
1114
1115    assert_send::<Poller>();
1116    assert_sync::<Poller>();
1117
1118    assert_send::<Event>();
1119    assert_sync::<Event>();
1120
1121    assert_send::<Events>();
1122    // Events can be !Sync
1123}