Skip to main content

compio_compat\sys/
windows.rs

1use std::{
2    io,
3    os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle, RawHandle},
4    time::Duration,
5};
6
7use compio_driver::AsRawFd;
8use compio_runtime::Runtime;
9use windows_sys::Win32::{
10    Foundation::{WAIT_FAILED, WAIT_TIMEOUT},
11    System::Threading::{CreateEventW, INFINITE, SetEvent, WaitForMultipleObjects},
12};
13
14use crate::sys::Adapter;
15
16struct WindowsAdapter {
17    runtime: Runtime,
18}
19
20impl WindowsAdapter {
21    fn new(runtime: Runtime) -> io::Result<Self> {
22        Ok(Self { runtime })
23    }
24
25    async fn wait(&self, timeout: Option<Duration>) -> io::Result<()> {
26        let (sender, receiver) = futures_channel::oneshot::channel::<io::Result<()>>();
27        let event = unsafe { CreateEventW(std::ptr::null(), 0, 0, std::ptr::null()) };
28        if event.is_null() {
29            return Err(io::Error::last_os_error());
30        }
31        let event_handle = unsafe { OwnedHandle::from_raw_handle(event as RawHandle) };
32
33        let timeout = match timeout {
34            Some(timeout) => timeout.as_millis() as u32,
35            None => INFINITE,
36        };
37
38        struct EventGuard(OwnedHandle);
39
40        impl Drop for EventGuard {
41            fn drop(&mut self) {
42                unsafe { SetEvent(self.0.as_raw_handle()) };
43            }
44        }
45
46        let _event_handle = EventGuard(event_handle);
47        let event = event as usize;
48        let driver = self.runtime.as_raw_fd() as usize;
49        windows_threading::submit(move || {
50            let handles = [event as RawHandle, driver as RawHandle];
51            let res = unsafe { WaitForMultipleObjects(2, handles.as_ptr(), 0, timeout) };
52            let res = match res {
53                WAIT_FAILED => Err(io::Error::last_os_error()),
54                WAIT_TIMEOUT => Err(io::ErrorKind::TimedOut.into()),
55                _ => Ok(()),
56            };
57            sender.send(res).ok();
58        });
59        receiver
60            .await
61            .map_err(|_| io::ErrorKind::Interrupted.into())
62            .flatten()
63    }
64}
65
66macro_rules! impl_adapter {
67    ($(#[$($attr:meta)*])? $name:ident) => {
68        $(#[$($attr)*])?
69        pub struct $name(WindowsAdapter);
70
71        impl Adapter for $name {
72            fn new(runtime: Runtime) -> io::Result<Self> {
73                WindowsAdapter::new(runtime).map(Self)
74            }
75
76            async fn wait(&self, timeout: Option<Duration>) -> io::Result<()> {
77                self.0.wait(timeout).await
78            }
79
80            fn clear(&self) -> io::Result<()> {
81                Ok(())
82            }
83        }
84
85        impl std::ops::Deref for $name {
86            type Target = Runtime;
87
88            fn deref(&self) -> &Self::Target {
89                &self.0.runtime
90            }
91        }
92    };
93}
94
95#[cfg(feature = "tokio")]
96impl_adapter! {
97    /// Adapter for `tokio` runtime.
98    TokioAdapter
99}
100
101#[cfg(feature = "futures")]
102impl_adapter! {
103    /// Adapter for general runtime.
104    FuturesAdapter
105}