Skip to main content

compio_process/
windows.rs

1use std::{
2    io,
3    os::windows::{io::AsRawHandle, process::ExitStatusExt},
4    process,
5    task::Poll,
6};
7
8use compio_buf::{BufResult, IntoInner, IoBuf, IoBufMut};
9use compio_driver::{
10    BufferRef, OpCode, OpType, ResultTakeBuffer, ToSharedFd,
11    op::{BufResultExt, Read, ReadManaged, Write},
12    syscall,
13};
14use compio_io::{AsyncRead, AsyncReadManaged, AsyncWrite};
15use compio_runtime::Runtime;
16use windows_sys::Win32::System::{IO::OVERLAPPED, Threading::GetExitCodeProcess};
17
18use crate::{ChildStderr, ChildStdin, ChildStdout};
19
20struct WaitProcess {
21    child: process::Child,
22}
23
24impl WaitProcess {
25    pub fn new(child: process::Child) -> Self {
26        Self { child }
27    }
28}
29
30unsafe impl OpCode for WaitProcess {
31    type Control = ();
32
33    unsafe fn init(&mut self, _: &mut Self::Control) {}
34
35    fn op_type(&self, _: &Self::Control) -> OpType {
36        OpType::Event(self.child.as_raw_handle() as _)
37    }
38
39    unsafe fn operate(
40        &mut self,
41        _: &mut Self::Control,
42        _optr: *mut OVERLAPPED,
43    ) -> Poll<io::Result<usize>> {
44        let mut code = 0;
45        syscall!(
46            BOOL,
47            GetExitCodeProcess(self.child.as_raw_handle() as _, &mut code)
48        )?;
49        Poll::Ready(Ok(code as _))
50    }
51}
52
53pub async fn child_wait(child: process::Child) -> io::Result<process::ExitStatus> {
54    let op = WaitProcess::new(child);
55    let code = compio_runtime::submit(op).await.0?;
56    Ok(process::ExitStatus::from_raw(code as _))
57}
58
59impl AsyncRead for ChildStdout {
60    async fn read<B: IoBufMut>(&mut self, buffer: B) -> BufResult<usize, B> {
61        let fd = self.to_shared_fd();
62        let op = Read::new(fd, buffer);
63        let res = compio_runtime::submit(op).await.into_inner();
64        unsafe { res.map_advanced() }
65    }
66}
67
68impl AsyncReadManaged for ChildStdout {
69    type Buffer = BufferRef;
70
71    async fn read_managed(&mut self, len: usize) -> io::Result<Option<Self::Buffer>> {
72        let fd = self.to_shared_fd();
73        let res = Runtime::with_current(|rt| {
74            let buffer_pool = rt.buffer_pool()?;
75            let op = ReadManaged::new(fd, &buffer_pool, len)?;
76            io::Result::Ok(rt.submit(op))
77        })?
78        .await;
79        unsafe { res.take_buffer() }
80    }
81}
82
83impl AsyncRead for ChildStderr {
84    async fn read<B: IoBufMut>(&mut self, buffer: B) -> BufResult<usize, B> {
85        let fd = self.to_shared_fd();
86        let op = Read::new(fd, buffer);
87        let res = compio_runtime::submit(op).await.into_inner();
88        unsafe { res.map_advanced() }
89    }
90}
91
92impl AsyncReadManaged for ChildStderr {
93    type Buffer = BufferRef;
94
95    async fn read_managed(&mut self, len: usize) -> io::Result<Option<Self::Buffer>> {
96        let fd = self.to_shared_fd();
97        let res = Runtime::with_current(|rt| {
98            let buffer_pool = rt.buffer_pool()?;
99            let op = ReadManaged::new(fd, &buffer_pool, len)?;
100            io::Result::Ok(rt.submit(op))
101        })?
102        .await;
103        unsafe { res.take_buffer() }
104    }
105}
106
107impl AsyncWrite for ChildStdin {
108    async fn write<T: IoBuf>(&mut self, buffer: T) -> BufResult<usize, T> {
109        let fd = self.to_shared_fd();
110        let op = Write::new(fd, buffer);
111        compio_runtime::submit(op).await.into_inner()
112    }
113
114    async fn flush(&mut self) -> io::Result<()> {
115        Ok(())
116    }
117
118    async fn shutdown(&mut self) -> io::Result<()> {
119        Ok(())
120    }
121}