@@ -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,98 @@ 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
+ // On two lines to circumvent a mutable borrow check failure.
866
+ let child = self . std . spawn ( ) ?;
867
+ self . build_child ( child)
868
+ }
869
+
870
+ /// Executes the command as a child process with a custom spawning function,
871
+ /// returning a handle to it.
872
+ ///
873
+ /// This is identical to [`Self::spawn`] in every aspect except the spawn:
874
+ /// here, it is customizable through the `with` parameter instead of
875
+ /// defaulting to the usual spawn. In fact, [`Self::spawn`] is just
876
+ /// [`Self::spawn_with`] with [`StdCommand::spawn`].
877
+ ///
878
+ /// This is useful mostly under Windows for now, since the platform exposes
879
+ /// special APIs to configure child processes when spawning them with various
880
+ /// attributes that customize the exact behavior of the spawn operation.
881
+ ///
882
+ /// # Examples
883
+ ///
884
+ /// Basic usage:
885
+ ///
886
+ /// ```no_run
887
+ /// # async fn test() { // allow using await
888
+ /// use std::process::Stdio;
889
+ ///
890
+ /// let output = tokio::process::Command::new("ls")
891
+ /// .stdin(Stdio::null())
892
+ /// .stdout(Stdio::piped())
893
+ /// .stderr(Stdio::piped())
894
+ /// .spawn_with(std::process::Command::spawn)
895
+ /// .unwrap()
896
+ /// .wait_with_output()
897
+ /// .await
898
+ /// .unwrap();
899
+ /// # }
900
+ /// ```
901
+ ///
902
+ /// Actually customizing the spawn under Windows:
903
+ ///
904
+ /// ```ignore
905
+ /// # #![feature(windows_process_extensions_raw_attribute)]
906
+ /// # #[cfg(windows)] // Windows-only nightly APIs are used here.
907
+ /// # async fn test() { // Allow using await.
908
+ /// use std::os::windows::process::{CommandExt, ProcThreadAttributeList};
909
+ /// use std::process::Stdio;
910
+ /// use tokio::process::Command;
911
+ ///
912
+ /// let parent = Command::new("cmd").spawn().unwrap();
913
+ /// let parent_process_handle = parent.raw_handle();
914
+ ///
915
+ /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
916
+ /// let attribute_list = ProcThreadAttributeList::build()
917
+ /// .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
918
+ /// .finish()
919
+ /// .unwrap();
920
+ ///
921
+ /// let _output = Command::new("ls")
922
+ /// .stdin(Stdio::null())
923
+ /// .stdout(Stdio::piped())
924
+ /// .stderr(Stdio::piped())
925
+ /// .spawn_with(|cmd| cmd.spawn_with_attributes(&attribute_list))
926
+ /// .unwrap()
927
+ /// .wait_with_output()
928
+ /// .await
929
+ /// .unwrap();
930
+ /// # }
931
+ /// ```
932
+ #[ cfg( tokio_unstable) ]
933
+ #[ cfg_attr( docsrs, doc( cfg( tokio_unstable) ) ) ]
934
+ #[ inline]
935
+ pub fn spawn_with (
936
+ & mut self ,
937
+ with : impl Fn ( & mut StdCommand ) -> io:: Result < StdChild > ,
938
+ ) -> io:: Result < Child > {
939
+ // On two lines to circumvent a mutable borrow check failure.
940
+ let child = with ( & mut self . std ) ?;
941
+ self . build_child ( child)
942
+ }
943
+
944
+ /// Small indirection for the spawn implementations.
945
+ ///
946
+ /// This is introduced for [`Self::spawn`] and [`Self::spawn_with`] to use:
947
+ /// [`Self::spawn`] cannot depend directly on on [`Self::spawn_with`] since
948
+ /// it is behind `tokio_unstable`. It also serves as a way to reduce
949
+ /// monomorphization bloat by taking in an already-spawned child process
950
+ /// instead of a command and custom spawn function.
951
+ fn build_child ( & self , child : StdChild ) -> io:: Result < Child > {
952
+ let spawned_child = imp:: build_child ( child) ?;
953
+
954
+ Ok ( Child {
865
955
child : FusedChild :: Child ( ChildDropGuard {
866
956
inner : spawned_child. child ,
867
957
kill_on_drop : self . kill_on_drop ,
0 commit comments