compio_process/
windows.rs

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