about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-06-20 14:56:38 +0200
committerGitHub <noreply@github.com>2022-06-20 14:56:38 +0200
commit85f1de20e76001db54d64ee0c3f9fec797075938 (patch)
treea3a48b7d1e82a50ff787ec06c0e055becfd09981
parent625c929a9fecc7fbaf7142faaab787ba8125a62f (diff)
parent740a54c69b1c426c2b08329ea278140eb0059d42 (diff)
downloadrust-85f1de20e76001db54d64ee0c3f9fec797075938.tar.gz
rust-85f1de20e76001db54d64ee0c3f9fec797075938.zip
Rollup merge of #97149 - ChrisDenton:win_async_pipes, r=m-ou-se
Windows: `CommandExt::async_pipes`

Discussed in https://github.com/tokio-rs/tokio/issues/4670 was the need for third party crates to be able to force `process::Command::spawn` to create pipes as async.

This implements the suggestion for a `async_pipes` method that gives third party crates that option.

# Example:

```rust
use std::process::{Command, Stdio};

Command::new("cmd")
    .async_pipes(true)
    .stdin(Stdio::piped())
    .stdout(Stdio::piped())
    .stderr(Stdio::piped())
    .spawn()
    .unwrap();
```
-rw-r--r--library/std/src/os/windows/process.rs40
1 files changed, 40 insertions, 0 deletions
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 24b0888b112..a6b75493e6e 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -161,6 +161,37 @@ pub trait CommandExt: Sealed {
     /// `CommandLineToArgvW` escaping rules.
     #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
     fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
+
+    /// When [`process::Command`] creates pipes, request that our side is always async.
+    ///
+    /// By default [`process::Command`] may choose to use pipes where both ends
+    /// are opened for synchronous read or write operations. By using
+    /// `async_pipes(true)`, this behavior is overridden so that our side is
+    /// always async.
+    ///
+    /// This is important because if doing async I/O a pipe or a file has to be
+    /// opened for async access.
+    ///
+    /// The end of the pipe sent to the child process will always be synchronous
+    /// regardless of this option.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(windows_process_extensions_async_pipes)]
+    /// use std::os::windows::process::CommandExt;
+    /// use std::process::{Command, Stdio};
+    ///
+    /// # let program = "";
+    ///
+    /// Command::new(program)
+    ///     .async_pipes(true)
+    ///     .stdin(Stdio::piped())
+    ///     .stdout(Stdio::piped())
+    ///     .stderr(Stdio::piped());
+    /// ```
+    #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
+    fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
 }
 
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -179,6 +210,15 @@ impl CommandExt for process::Command {
         self.as_inner_mut().raw_arg(raw_text.as_ref());
         self
     }
+
+    fn async_pipes(&mut self, always_async: bool) -> &mut process::Command {
+        // FIXME: This currently has an intentional no-op implementation.
+        // For the time being our side of the pipes will always be async.
+        // Once the ecosystem has adjusted, we may then be able to start making
+        // use of synchronous pipes within the standard library.
+        let _ = always_async;
+        self
+    }
 }
 
 #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]