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