pal_async/
wait.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Wait-related functionality.
5
6use crate::driver::Driver;
7use crate::driver::PollImpl;
8use std::future::Future;
9use std::future::poll_fn;
10use std::io;
11#[cfg(unix)]
12use std::os::unix::prelude::*;
13#[cfg(windows)]
14use std::os::windows::prelude::*;
15use std::task::Context;
16use std::task::Poll;
17
18/// A trait for driving kernel event (Windows events or Unix eventfd) waits.
19pub trait WaitDriver: Unpin {
20    /// The wait object.
21    type Wait: 'static + PollWait;
22
23    /// Creates a new wait.
24    #[cfg(windows)]
25    fn new_wait(&self, handle: RawHandle) -> io::Result<Self::Wait>;
26    /// Creates a new wait.
27    ///
28    /// Signals will be consumed using reads of `read_size` bytes, with 8-byte
29    /// buffer alignment. `read_size` must be at most [`MAXIMUM_WAIT_READ_SIZE`]
30    /// bytes.
31    #[cfg(unix)]
32    fn new_wait(&self, fd: RawFd, read_size: usize) -> io::Result<Self::Wait>;
33}
34
35/// The maximum `read_size` for [`WaitDriver::new_wait`].
36#[cfg(unix)]
37pub const MAXIMUM_WAIT_READ_SIZE: usize = 8;
38
39/// A trait for polling the state of waits.
40pub trait PollWait: Unpin + Send + Sync {
41    /// Polls a wait for completion, consuming the object's wait signal.
42    ///
43    /// Depending on the wait object, this may fail. For platform events (e.g.,
44    /// eventfd on Linux, and NT events on Windows), this cannot fail.
45    fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
46
47    /// Cancels a polled wait.
48    ///
49    /// Returns true if the wait signal was consumed.
50    fn poll_cancel_wait(&mut self, cx: &mut Context<'_>) -> Poll<bool>;
51}
52
53impl std::fmt::Debug for dyn PollWait {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        f.pad("PollWait")
56    }
57}
58
59/// A polled wait object.
60#[derive(Debug)]
61pub struct PolledWait<T> {
62    wait: PollImpl<dyn PollWait>,
63    event: T,
64}
65
66#[cfg(windows)]
67impl<T: AsHandle> PolledWait<T> {
68    /// Returns a new polled wait object wrapping `event`.
69    ///
70    /// Typically `T` will be [`pal_event::Event`].
71    pub fn new(driver: &(impl ?Sized + Driver), event: T) -> io::Result<Self> {
72        let wait = driver.new_dyn_wait(event.as_handle().as_raw_handle())?;
73        Ok(Self { wait, event })
74    }
75}
76
77#[cfg(unix)]
78impl<T: AsFd> PolledWait<T> {
79    /// Returns a new polled wait object wrapping `event`.
80    ///
81    /// Typically `T` will be [`pal_event::Event`]. The read size for consuming the
82    /// fd's signal will be 8 bytes to match the behavior of eventfd.
83    pub fn new(driver: &(impl ?Sized + Driver), event: T) -> io::Result<Self> {
84        Self::new_with_size(driver, event, 8)
85    }
86
87    /// Returns a new polled wait object wrapping `event`, with a specific sized
88    /// read to consume the event.
89    pub fn new_with_size(
90        driver: &(impl ?Sized + Driver),
91        event: T,
92        read_size: usize,
93    ) -> io::Result<Self> {
94        let wait = driver.new_dyn_wait(event.as_fd().as_raw_fd(), read_size)?;
95        Ok(Self { wait, event })
96    }
97}
98
99impl<T> PolledWait<T> {
100    /// Returns the inner wait object.
101    ///
102    /// With some drivers, this may leak a signal.
103    pub fn into_inner(self) -> T {
104        self.event
105    }
106
107    /// Gets a reference to the inner wait object.
108    pub fn get(&self) -> &T {
109        &self.event
110    }
111
112    /// Polls for the wait object to be signaled.
113    pub fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
114        self.wait.poll_wait(cx)
115    }
116
117    /// Waits for the wait object to be signaled.
118    pub fn wait(&mut self) -> impl '_ + Unpin + Future<Output = io::Result<()>> {
119        poll_fn(move |cx| self.poll_wait(cx))
120    }
121}