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, Recv, RecvManaged, ResultTakeBuffer, Send},
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 = Recv::new(fd, buffer);
56        compio_runtime::submit(op).await.into_inner().map_advanced()
57    }
58}
59
60impl AsyncReadManaged for ChildStdout {
61    type Buffer<'a> = BorrowedBuffer<'a>;
62    type BufferPool = BufferPool;
63
64    async fn read_managed<'a>(
65        &mut self,
66        buffer_pool: &'a Self::BufferPool,
67        len: usize,
68    ) -> io::Result<Self::Buffer<'a>> {
69        let fd = self.to_shared_fd();
70        let buffer_pool = buffer_pool.try_inner()?;
71        let op = RecvManaged::new(fd, buffer_pool, len)?;
72        compio_runtime::submit_with_flags(op)
73            .await
74            .take_buffer(buffer_pool)
75    }
76}
77
78impl AsyncRead for ChildStderr {
79    async fn read<B: IoBufMut>(&mut self, buffer: B) -> BufResult<usize, B> {
80        let fd = self.to_shared_fd();
81        let op = Recv::new(fd, buffer);
82        compio_runtime::submit(op).await.into_inner().map_advanced()
83    }
84}
85
86impl AsyncReadManaged for ChildStderr {
87    type Buffer<'a> = BorrowedBuffer<'a>;
88    type BufferPool = BufferPool;
89
90    async fn read_managed<'a>(
91        &mut self,
92        buffer_pool: &'a Self::BufferPool,
93        len: usize,
94    ) -> io::Result<Self::Buffer<'a>> {
95        let fd = self.to_shared_fd();
96        let buffer_pool = buffer_pool.try_inner()?;
97        let op = RecvManaged::new(fd, buffer_pool, len)?;
98        compio_runtime::submit_with_flags(op)
99            .await
100            .take_buffer(buffer_pool)
101    }
102}
103
104impl AsyncWrite for ChildStdin {
105    async fn write<T: IoBuf>(&mut self, buffer: T) -> BufResult<usize, T> {
106        let fd = self.to_shared_fd();
107        let op = Send::new(fd, buffer);
108        compio_runtime::submit(op).await.into_inner()
109    }
110
111    async fn flush(&mut self) -> io::Result<()> {
112        Ok(())
113    }
114
115    async fn shutdown(&mut self) -> io::Result<()> {
116        Ok(())
117    }
118}