@@ -249,7 +249,7 @@ use std::future::Future;
249249use std:: io;
250250use std:: path:: Path ;
251251use 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 } ;
253253use std:: task:: { ready, Context , Poll } ;
254254
255255#[ cfg( unix) ]
@@ -860,8 +860,98 @@ impl Command {
860860 /// On Unix platforms this method will fail with `std::io::ErrorKind::WouldBlock`
861861 /// if the system process limit is reached (which includes other applications
862862 /// running on the system).
863+ #[ inline]
863864 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 {
865955 child : FusedChild :: Child ( ChildDropGuard {
866956 inner : spawned_child. child ,
867957 kill_on_drop : self . kill_on_drop ,
0 commit comments