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