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}