1use std::{
6 task::{Poll, Waker},
7 time::Instant,
8};
9
10use mio::Token;
11use rasi_syscall::{register_global_timer, Handle, Timer};
12
13use crate::{reactor::global_reactor, TokenSequence};
14
15pub(crate) struct TimerHandle {
16 deadline: Instant,
17 token: Token,
18}
19
20impl TimerHandle {
21 pub(crate) fn new(token: Token, deadline: Instant) -> Handle {
22 Handle::new(TimerHandle { token, deadline })
23 }
24}
25
26#[derive(Debug, Default)]
28pub struct MioTimer {}
29
30impl Timer for MioTimer {
31 fn deadline(
32 &self,
33 waker: Waker,
34 deadline: std::time::Instant,
35 ) -> std::io::Result<Option<rasi_syscall::Handle>> {
36 let token = Token::next();
37
38 Ok(global_reactor()
39 .deadline(token, waker, deadline)
40 .map(|_| TimerHandle::new(token, deadline)))
41 }
42
43 fn timeout_wait(
44 &self,
45 waker: std::task::Waker,
46 handle: &rasi_syscall::Handle,
47 ) -> std::task::Poll<()> {
48 let time_handle = handle
49 .downcast::<TimerHandle>()
50 .expect("Expect TimeHandle.");
51
52 match global_reactor().deadline(time_handle.token, waker, time_handle.deadline) {
53 Some(_) => Poll::Pending,
54 None => Poll::Ready(()),
55 }
56 }
57}
58
59pub fn register_mio_timer() {
63 register_global_timer(MioTimer::default())
64}
65
66#[cfg(test)]
67mod tests {
68 use std::sync::OnceLock;
69
70 use rasi_spec::timer::run_timer_spec;
71
72 use super::MioTimer;
73
74 static INIT: OnceLock<Box<dyn rasi_syscall::Timer>> = OnceLock::new();
75
76 fn get_syscall() -> &'static dyn rasi_syscall::Timer {
77 INIT.get_or_init(|| Box::new(MioTimer::default())).as_ref()
78 }
79
80 #[futures_test::test]
81 async fn test_timeout() {
82 run_timer_spec(get_syscall()).await;
83 }
84}