@@ -62,6 +62,60 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
6262 // A 64kb pipe capacity is the same as a typical Linux default.
6363 const PIPE_BUFFER_CAPACITY : u32 = 64 * 1024 ;
6464
65+ // Since Windows 9X/ME does not support creating named pipes (only connecting to remote pipes
66+ // created on NT), we'll have to make do with anonymous pipes, without overlapped I/O. In
67+ // particular, this means that we'll have to do reading from two threads in the case where both
68+ // stdout and stderr being piped (see `read2`).
69+
70+ // 9X/ME *does* have a kernel32 export entry for `CreateNamedPipe`, so an availability check
71+ // would not work. We're just gonna check the bit that's only set on non-unicode Windows
72+ // versions instead...
73+
74+ // The `AnonPipe` impl used in `read2` below needs to be able to cancel the overlapped i/o
75+ // operation, so we also have to check for `CancelIo` being available. This means that the
76+ // "modern" path is taken only for NT4+.
77+ if !crate :: sys:: compat:: supports_async_io ( ) {
78+ let size = mem:: size_of :: < c:: SECURITY_ATTRIBUTES > ( ) ;
79+ let mut sa = c:: SECURITY_ATTRIBUTES {
80+ nLength : size as c:: DWORD ,
81+ lpSecurityDescriptor : ptr:: null_mut ( ) ,
82+ // We follow the old "Creating a Child Process with Redirected Input and Output" MSDN
83+ // entry (pre-`SetHandleInformation`) here, duplicating the handle that is not being
84+ // sent to the child process as non-inheritable and then closing the inheritable one.
85+ // Usually, this would be racy, but this function is only called in `Stdio::to_handle`,
86+ // which is in turn only called form `process::spawn`, which acquires a lock on process
87+ // spawning because of this.
88+ bInheritHandle : c:: TRUE ,
89+ } ;
90+
91+ unsafe {
92+ let mut read_pipe = mem:: zeroed ( ) ;
93+ let mut write_pipe = mem:: zeroed ( ) ;
94+ crate :: sys:: cvt ( c:: CreatePipe (
95+ & mut read_pipe,
96+ & mut write_pipe,
97+ & mut sa,
98+ PIPE_BUFFER_CAPACITY ,
99+ ) ) ?;
100+ let read_pipe = Handle :: from_raw_handle ( read_pipe) ;
101+ let write_pipe = Handle :: from_raw_handle ( write_pipe) ;
102+
103+ let ( ours_inheritable, theirs) =
104+ if ours_readable { ( read_pipe, write_pipe) } else { ( write_pipe, read_pipe) } ;
105+
106+ // Make `ours` non-inheritable by duplicating it with the approriate setting
107+ let ours = ours_inheritable. duplicate ( 0 , false , c:: DUPLICATE_SAME_ACCESS ) ?;
108+
109+ // close the old, inheritable handle to the pipe end that is ours
110+ drop ( ours_inheritable) ;
111+
112+ return Ok ( Pipes {
113+ ours : AnonPipe { inner : ours } ,
114+ theirs : AnonPipe { inner : theirs } ,
115+ } ) ;
116+ }
117+ }
118+
65119 // Note that we specifically do *not* use `CreatePipe` here because
66120 // unfortunately the anonymous pipes returned do not support overlapped
67121 // operations. Instead, we create a "hopefully unique" name and create a
@@ -243,6 +297,10 @@ impl AnonPipe {
243297 }
244298
245299 pub fn read ( & self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
300+ if !crate :: sys:: compat:: supports_async_io ( ) {
301+ return self . inner . read ( buf) ;
302+ }
303+
246304 let result = unsafe {
247305 let len = crate :: cmp:: min ( buf. len ( ) , c:: DWORD :: MAX as usize ) as c:: DWORD ;
248306 self . alertable_io_internal ( c:: ReadFileEx , buf. as_mut_ptr ( ) as _ , len)
@@ -259,6 +317,10 @@ impl AnonPipe {
259317 }
260318
261319 pub fn read_buf ( & self , mut buf : BorrowedCursor < ' _ > ) -> io:: Result < ( ) > {
320+ if !crate :: sys:: compat:: supports_async_io ( ) {
321+ return self . inner . read_buf ( buf) ;
322+ }
323+
262324 let result = unsafe {
263325 let len = crate :: cmp:: min ( buf. capacity ( ) , c:: DWORD :: MAX as usize ) as c:: DWORD ;
264326 self . alertable_io_internal ( c:: ReadFileEx , buf. as_mut ( ) . as_mut_ptr ( ) as _ , len)
@@ -294,6 +356,10 @@ impl AnonPipe {
294356 }
295357
296358 pub fn write ( & self , buf : & [ u8 ] ) -> io:: Result < usize > {
359+ if !crate :: sys:: compat:: supports_async_io ( ) {
360+ return self . inner . write ( buf) ;
361+ }
362+
297363 unsafe {
298364 let len = crate :: cmp:: min ( buf. len ( ) , c:: DWORD :: MAX as usize ) as c:: DWORD ;
299365 self . alertable_io_internal ( c:: WriteFileEx , buf. as_ptr ( ) as _ , len)
@@ -408,6 +474,25 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) ->
408474 let p1 = p1. into_handle ( ) ;
409475 let p2 = p2. into_handle ( ) ;
410476
477+ if !crate :: sys:: compat:: supports_async_io ( ) {
478+ use crate :: io:: Read ;
479+
480+ // Since we are using anonymous pipes (= without overlapped I/O support) here, we can't do
481+ // async waiting on both stdout and stderr at the same time on one thread, so we have to
482+ // spawn an additional thread to do the waiting for the second pipe.
483+
484+ // See https://github.com/rust-lang/rust/pull/31618, where this was removed initially.
485+ let second_pipe = crate :: thread:: spawn ( move || {
486+ let mut ret = Vec :: new ( ) ;
487+ ( & p2) . read_to_end ( & mut ret) . map ( |_| ret)
488+ } ) ;
489+
490+ ( & p1) . read_to_end ( v1) ?;
491+ * v2 = second_pipe. join ( ) . unwrap ( ) ?;
492+
493+ return Ok ( ( ) ) ;
494+ }
495+
411496 let mut p1 = AsyncPipe :: new ( p1, v1) ?;
412497 let mut p2 = AsyncPipe :: new ( p2, v2) ?;
413498 let objs = [ p1. event . as_raw_handle ( ) , p2. event . as_raw_handle ( ) ] ;
0 commit comments