hala_io/
sleep.rs

1use std::{
2    future::Future,
3    io,
4    task::{Context, Poll},
5    time::Duration,
6};
7
8use crate::context::{io_context, RawIoContext};
9
10use super::{Cmd, Description, Driver, Handle, Interest, OpenFlags};
11
12/// Future type to suspend current task for a while
13pub struct Sleep {
14    fd: Option<Handle>,
15    driver: Driver,
16    expired: Duration,
17    poller: Handle,
18}
19
20impl Sleep {
21    /// Create a [`Sleep`] instance with suspend `expired` interval.
22    pub fn new_with(driver: Driver, poller: Handle, expired: Duration) -> io::Result<Self> {
23        Ok(Self {
24            fd: None,
25            driver,
26            expired,
27            poller,
28        })
29    }
30}
31
32impl Future for Sleep {
33    type Output = io::Result<()>;
34
35    fn poll(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
36        // first time, create timeout fd
37        if self.fd.is_none() {
38            let fd = match self
39                .driver
40                .fd_open(Description::Timeout, OpenFlags::Duration(self.expired))
41            {
42                Err(err) => return Poll::Ready(Err(err)),
43                Ok(fd) => fd,
44            };
45
46            self.fd = Some(fd);
47
48            match self.driver.fd_cntl(
49                self.poller,
50                Cmd::Register {
51                    source: fd,
52                    interests: Interest::Readable,
53                },
54            ) {
55                Err(err) => return Poll::Ready(Err(err)),
56                _ => {}
57            }
58
59            log::trace!("create timeout {:?}", fd);
60        }
61
62        // try check status of timeout fd
63        match self
64            .driver
65            .fd_cntl(self.fd.unwrap(), Cmd::Timeout(cx.waker().clone()))
66        {
67            Ok(resp) => match resp.try_into_timeout() {
68                Ok(status) => {
69                    if status {
70                        return Poll::Ready(Ok(()));
71                    }
72                }
73
74                Err(err) => {
75                    return Poll::Ready(Err(err));
76                }
77            },
78            Err(err) => return Poll::Ready(Err(err)),
79        }
80
81        return Poll::Pending;
82    }
83}
84
85impl Drop for Sleep {
86    fn drop(&mut self) {
87        if let Some(fd) = self.fd.take() {
88            self.driver.fd_close(fd).unwrap();
89        }
90    }
91}
92
93/// Sleep for a while
94pub async fn sleep(duration: Duration) -> io::Result<()> {
95    let context = io_context();
96
97    Sleep::new_with(context.driver().clone(), context.poller(), duration)?.await
98}