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