@@ -249,7 +249,7 @@ use std::future::Future;
249
249
use std:: io;
250
250
use std:: path:: Path ;
251
251
use std:: pin:: Pin ;
252
- use std:: process:: { Command as StdCommand , ExitStatus , Output , Stdio } ;
252
+ use std:: process:: { Child as StdChild , Command as StdCommand , ExitStatus , Output , Stdio } ;
253
253
use std:: task:: { ready, Context , Poll } ;
254
254
255
255
#[ cfg( unix) ]
@@ -860,8 +860,78 @@ impl Command {
860
860
/// On Unix platforms this method will fail with `std::io::ErrorKind::WouldBlock`
861
861
/// if the system process limit is reached (which includes other applications
862
862
/// running on the system).
863
+ #[ inline]
863
864
pub fn spawn ( & mut self ) -> io:: Result < Child > {
864
- imp:: spawn_child ( & mut self . std ) . map ( |spawned_child| Child {
865
+ self . spawn_with ( StdCommand :: spawn)
866
+ }
867
+
868
+ /// Executes the command as a child process with a custom spawning function,
869
+ /// returning a handle to it.
870
+ ///
871
+ /// This is identical to [`Self::spawn`] in every aspect except the spawn:
872
+ /// here, it is customizable through the `with` parameter instead of
873
+ /// defaulting to the usual spawn. In fact, [`Self::spawn`] is just
874
+ /// [`Self::spawn_with`] with [`StdCommand::spawn`].
875
+ ///
876
+ /// This is useful mostly under Windows for now, since the platform exposes
877
+ /// special APIs to configure child processes when spawning them with various
878
+ /// attributes that customize the exact behavior of the spawn operation.
879
+ ///
880
+ /// # Examples
881
+ ///
882
+ /// Basic usage:
883
+ ///
884
+ /// ```no_run
885
+ /// # async fn test() { // allow using await
886
+ /// use std::process::Stdio;
887
+ ///
888
+ /// let output = tokio::process::Command::new("ls")
889
+ /// .stdin(Stdio::null())
890
+ /// .stdout(Stdio::piped())
891
+ /// .stderr(Stdio::piped())
892
+ /// .spawn_with(std::process::Command::spawn)
893
+ /// .unwrap()
894
+ /// .wait_with_output()
895
+ /// .await
896
+ /// .unwrap();
897
+ /// # }
898
+ /// ```
899
+ ///
900
+ /// Actually customizing the spawn under Windows:
901
+ ///
902
+ /// ```ignore
903
+ /// # #[cfg(windows)] // Windows-only nightly APIs are used here.
904
+ /// # async fn test() { // Allow using await.
905
+ /// use std::os::windows::io::AsRawHandle;
906
+ /// use std::os::windows::process::{CommandExt, ProcThreadAttributeList};
907
+ /// use std::process::Stdio;
908
+ /// use tokio::process::Command;
909
+ ///
910
+ /// let parent = Command::new("cmd").spawn().unwrap();
911
+ /// let parent_process_handle = parent.as_raw_handle();
912
+ ///
913
+ /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
914
+ /// let mut attribute_list = ProcThreadAttributeList::build()
915
+ /// .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
916
+ /// .finish()
917
+ /// .unwrap();
918
+ ///
919
+ /// let output = Command::new("ls")
920
+ /// .stdin(Stdio::null())
921
+ /// .stdout(Stdio::piped())
922
+ /// .stderr(Stdio::piped())
923
+ /// .spawn_with(|cmd| cmd.spawn_with_attributes(&attribute_list))
924
+ /// .unwrap()
925
+ /// .wait_with_output()
926
+ /// .await
927
+ /// .unwrap();
928
+ /// # }
929
+ /// ```
930
+ pub fn spawn_with (
931
+ & mut self ,
932
+ with : impl Fn ( & mut StdCommand ) -> io:: Result < StdChild > ,
933
+ ) -> io:: Result < Child > {
934
+ imp:: spawn_child_with ( & mut self . std , with) . map ( |spawned_child| Child {
865
935
child : FusedChild :: Child ( ChildDropGuard {
866
936
inner : spawned_child. child ,
867
937
kill_on_drop : self . kill_on_drop ,
0 commit comments