Skip to content

Commit 9013054

Browse files
committed
Windows: Use a pipe relay for chaining pipes
1 parent e745b4d commit 9013054

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

library/std/src/sys/windows/pipe.rs

+43
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,46 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
162162
}
163163
}
164164

165+
/// Takes an asynchronous source pipe and returns a synchronous pipe suitable
166+
/// for sending to a child process.
167+
///
168+
/// This is achieved by creating a new set of pipes and spawning a thread that
169+
/// relays messages between the source and the synchronous pipe.
170+
pub fn spawn_pipe_relay(
171+
source: &AnonPipe,
172+
ours_readable: bool,
173+
their_handle_inheritable: bool,
174+
) -> io::Result<AnonPipe> {
175+
// We need this handle to live for the lifetime of the thread spawned below.
176+
let source = source.duplicate()?;
177+
178+
// create a new pair of anon pipes.
179+
let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?;
180+
181+
// Spawn a thread that passes messages from one pipe to the other.
182+
// Any errors will simply cause the thread to exit.
183+
let (reader, writer) = if ours_readable { (ours, source) } else { (source, ours) };
184+
crate::thread::spawn(move || {
185+
let mut buf = [0_u8; 4096];
186+
'reader: while let Ok(len) = reader.read(&mut buf) {
187+
if len == 0 {
188+
break;
189+
}
190+
let mut start = 0;
191+
while let Ok(written) = writer.write(&buf[start..len]) {
192+
start += written;
193+
if start == len {
194+
continue 'reader;
195+
}
196+
}
197+
break;
198+
}
199+
});
200+
201+
// Return the pipe that should be sent to the child process.
202+
Ok(theirs)
203+
}
204+
165205
fn random_number() -> usize {
166206
static N: AtomicUsize = AtomicUsize::new(0);
167207
loop {
@@ -189,6 +229,9 @@ impl AnonPipe {
189229
pub fn into_handle(self) -> Handle {
190230
self.inner
191231
}
232+
fn duplicate(&self) -> io::Result<Self> {
233+
self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| AnonPipe { inner })
234+
}
192235

193236
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
194237
let result = unsafe {

library/std/src/sys/windows/process.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ pub enum Stdio {
172172
Inherit,
173173
Null,
174174
MakePipe,
175+
Pipe(AnonPipe),
175176
Handle(Handle),
176177
}
177178

@@ -528,6 +529,11 @@ impl Stdio {
528529
Ok(pipes.theirs.into_handle())
529530
}
530531

532+
Stdio::Pipe(ref source) => {
533+
let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
534+
pipe::spawn_pipe_relay(source, ours_readable, true).map(AnonPipe::into_handle)
535+
}
536+
531537
Stdio::Handle(ref handle) => handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS),
532538

533539
// Open up a reference to NUL with appropriate read/write
@@ -552,7 +558,7 @@ impl Stdio {
552558

553559
impl From<AnonPipe> for Stdio {
554560
fn from(pipe: AnonPipe) -> Stdio {
555-
Stdio::Handle(pipe.into_handle())
561+
Stdio::Pipe(pipe)
556562
}
557563
}
558564

0 commit comments

Comments
 (0)