fn new(cmd: &mut Command) -> io::Result<Child> {
        let mut child = cmd.inner.spawn()?;

        // Convert sync I/O types into async I/O types.
        let stdin = child.stdin.take().map(wrap).transpose()?.map(ChildStdin);
        let stdout = child.stdout.take().map(wrap).transpose()?.map(ChildStdout);
        let stderr = child.stderr.take().map(wrap).transpose()?.map(ChildStderr);

        cfg_if::cfg_if! {
            if #[cfg(windows)] {
                use std::os::windows::io::AsRawHandle;
                use std::sync::mpsc;

                use winapi::um::{
                    winbase::{RegisterWaitForSingleObject, INFINITE},
                    winnt::{BOOLEAN, HANDLE, PVOID, WT_EXECUTEINWAITTHREAD, WT_EXECUTEONLYONCE},
                };

                // This channel is used to simulate SIGCHLD on Windows.
                static CALLBACK: Lazy<(mpsc::SyncSender<()>, Mutex<mpsc::Receiver<()>>)> =
                    Lazy::new(|| {
                        let (s, r) = mpsc::sync_channel(1);
                        (s, Mutex::new(r))
                    });

                // Called when a child exits.
                unsafe extern "system" fn callback(_: PVOID, _: BOOLEAN) {
                    CALLBACK.0.try_send(()).ok();
                }

                // Register this child process to invoke `callback` on exit.
                let mut wait_object = std::ptr::null_mut();
                let ret = unsafe {
                    RegisterWaitForSingleObject(
                        &mut wait_object,
                        child.as_raw_handle() as HANDLE,
                        Some(callback),
                        std::ptr::null_mut(),
                        INFINITE,
                        WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE,
                    )
                };
                if ret == 0 {
                    return Err(io::Error::last_os_error());
                }

                // Waits for the next SIGCHLD signal.
                fn wait_sigchld() {
                    CALLBACK.1.lock().unwrap().recv().ok();
                }

                // Wraps a sync I/O type into an async I/O type.
                fn wrap<T>(io: T) -> io::Result<Unblock<T>> {
                    Ok(Unblock::new(io))
                }

            } else if #[cfg(unix)] {
                static SIGNALS: Lazy<signal_hook::iterator::Signals> = Lazy::new(|| {
                    signal_hook::iterator::Signals::new(&[signal_hook::SIGCHLD])
                        .expect("cannot set signal handler for SIGCHLD")
                });

                // Make sure the signal handler is registered before interacting with the process.
                Lazy::force(&SIGNALS);

                // Waits for the next SIGCHLD signal.
                fn wait_sigchld() {
                    SIGNALS.forever().next();
                }

                // Wraps a sync I/O type into an async I/O type.
                fn wrap<T: std::os::unix::io::AsRawFd>(io: T) -> io::Result<Async<T>> {
                    Async::new(io)
                }
            }
        }

        static ZOMBIES: Lazy<Mutex<Vec<std::process::Child>>> = Lazy::new(|| {
            // Start a thread that handles SIGCHLD and notifies tasks when child processes exit.
            thread::Builder::new()
                .name("async-process".to_string())
                .spawn(move || {
                    loop {
                        // Wait for the next SIGCHLD signal.
                        wait_sigchld();

                        // Notify all listeners waiting on the SIGCHLD event.
                        SIGCHLD.notify(std::usize::MAX);

                        // Reap zombie processes.
                        let mut zombies = ZOMBIES.lock().unwrap();
                        let mut i = 0;
                        while i < zombies.len() {
                            if let Ok(None) = zombies[i].try_wait() {
                                i += 1;
                            } else {
                                zombies.swap_remove(i);
                            }
                        }
                    }
                })
                .expect("cannot spawn async-process thread");

            Mutex::new(Vec::new())
        });

        // Make sure the thread is started.
        Lazy::force(&ZOMBIES);

        // When the last reference to the child process is dropped, push it into the zombie list.
        impl Drop for ChildGuard {
            fn drop(&mut self) {
                if self.reap_on_drop {
                    let mut zombies = ZOMBIES.lock().unwrap();
                    if let Ok(None) = self.get_mut().try_wait() {
                        zombies.push(self.inner.take().unwrap());
                    }
                }
            }
        }

        Ok(Child {
            stdin,
            stdout,
            stderr,
            child: Arc::new(Mutex::new(ChildGuard {
                inner: Some(child),
                reap_on_drop: cmd.reap_on_drop,
            })),
            kill_on_drop: cmd.kill_on_drop,
        })
    }
/// Wraps the inner child process handle and registers it in the global process list.
///
/// The "async-process" thread waits for processes in the global list and cleans up the
/// resources when they exit.
Wraps the inner child process handle and registers it in the global process list.
The "async-process" thread waits for processes in the global list and cleans up the
resources when they exit.
Wraps the inner child process handle and registers it in the global process list . The " async - process " thread waits for processes in the global list and cleans up the resources when they exit .
fn new(cmd: &mut Command) -> io::Result<Child> {
        let mut child = cmd.inner.spawn()?;
        // Convert sync I/O types into async I/O types.
        let stdin = child.stdin.take().map(wrap).transpose()?.map(ChildStdin);
        let stdout = child.stdout.take().map(wrap).transpose()?.map(ChildStdout);
        let stderr = child.stderr.take().map(wrap).transpose()?.map(ChildStderr);
        cfg_if::cfg_if! {
            if #[cfg(windows)] {
                use std::os::windows::io::AsRawHandle;
                use std::sync::mpsc;
                use winapi::um::{
                    winbase::{RegisterWaitForSingleObject, INFINITE},
                    winnt::{BOOLEAN, HANDLE, PVOID, WT_EXECUTEINWAITTHREAD, WT_EXECUTEONLYONCE},
                };
                // This channel is used to simulate SIGCHLD on Windows.
                static CALLBACK: Lazy<(mpsc::SyncSender<()>, Mutex<mpsc::Receiver<()>>)> =
                    Lazy::new(|| {
                        let (s, r) = mpsc::sync_channel(1);
                        (s, Mutex::new(r))
                    });
                // Called when a child exits.
                unsafe extern "system" fn callback(_: PVOID, _: BOOLEAN) {
                    CALLBACK.0.try_send(()).ok();
                }
                // Register this child process to invoke `callback` on exit.
                let mut wait_object = std::ptr::null_mut();
                let ret = unsafe {
                    RegisterWaitForSingleObject(
                        &mut wait_object,
                        child.as_raw_handle() as HANDLE,
                        Some(callback),
                        std::ptr::null_mut(),
                        INFINITE,
                        WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE,
                    )
                };
                if ret == 0 {
                    return Err(io::Error::last_os_error());
                }
                // Waits for the next SIGCHLD signal.
                fn wait_sigchld() {
                    CALLBACK.1.lock().unwrap().recv().ok();
                }
                // Wraps a sync I/O type into an async I/O type.
                fn wrap<T>(io: T) -> io::Result<Unblock<T>> {
                    Ok(Unblock::new(io))
                }
            } else if #[cfg(unix)] {
                static SIGNALS: Lazy<signal_hook::iterator::Signals> = Lazy::new(|| {
                    signal_hook::iterator::Signals::new(&[signal_hook::SIGCHLD])
                        .expect("cannot set signal handler for SIGCHLD")
                });
                // Make sure the signal handler is registered before interacting with the process.
                Lazy::force(&SIGNALS);
                // Waits for the next SIGCHLD signal.
                fn wait_sigchld() {
                    SIGNALS.forever().next();
                }
                // Wraps a sync I/O type into an async I/O type.
                fn wrap<T: std::os::unix::io::AsRawFd>(io: T) -> io::Result<Async<T>> {
                    Async::new(io)
                }
            }
        }
        static ZOMBIES: Lazy<Mutex<Vec<std::process::Child>>> = Lazy::new(|| {
            // Start a thread that handles SIGCHLD and notifies tasks when child processes exit.
            thread::Builder::new()
                .name("async-process".to_string())
                .spawn(move || {
                    loop {
                        // Wait for the next SIGCHLD signal.
                        wait_sigchld();
                        // Notify all listeners waiting on the SIGCHLD event.
                        SIGCHLD.notify(std::usize::MAX);
                        // Reap zombie processes.
                        let mut zombies = ZOMBIES.lock().unwrap();
                        let mut i = 0;
                        while i < zombies.len() {
                            if let Ok(None) = zombies[i].try_wait() {
                                i += 1;
                            } else {
                                zombies.swap_remove(i);
                            }
                        }
                    }
                })
                .expect("cannot spawn async-process thread");
            Mutex::new(Vec::new())
        });
        // Make sure the thread is started.
        Lazy::force(&ZOMBIES);
        // When the last reference to the child process is dropped, push it into the zombie list.
        impl Drop for ChildGuard {
            fn drop(&mut self) {
                if self.reap_on_drop {
                    let mut zombies = ZOMBIES.lock().unwrap();
                    if let Ok(None) = self.get_mut().try_wait() {
                        zombies.push(self.inner.take().unwrap());
                    }
                }
            }
        }
        Ok(Child {
            stdin,
            stdout,
            stderr,
            child: Arc::new(Mutex::new(ChildGuard {
                inner: Some(child),
                reap_on_drop: cmd.reap_on_drop,
            })),
            kill_on_drop: cmd.kill_on_drop,
        })
    }
fn new ( cmd : & mut Command ) -> io :: Result < Child > { let mut child = cmd . inner . spawn ( ) ? ; // Convert sync I/O types into async I/O types. let stdin = child . stdin . take ( ) . map ( wrap ) . transpose ( ) ? . map ( ChildStdin ) ; let stdout = child . stdout . take ( ) . map ( wrap ) . transpose ( ) ? . map ( ChildStdout ) ; let stderr = child . stderr . take ( ) . map ( wrap ) . transpose ( ) ? . map ( ChildStderr ) ; cfg_if :: cfg_if ! { if [ cfg ( windows ) ] { use std os windows io AsRawHandle use std sync mpsc use winapi um { winbase { RegisterWaitForSingleObject INFINITE } winnt { BOOLEAN HANDLE PVOID WT_EXECUTEINWAITTHREAD WT_EXECUTEONLYONCE } } // This channel is used to simulate SIGCHLD on Windows. static CALLBACK Lazy ( mpsc SyncSender ( ) Mutex mpsc Receiver ( ) ) Lazy new ( { let ( s r ) mpsc sync_channel ( 1 ) ( s Mutex new ( r ) ) } ) // Called when a child exits. unsafe extern " " fn callback ( PVOID BOOLEAN ) { CALLBACK 0 try_send ( ( ) ) ok ( ) } // Register this child process to invoke `callback` on exit. let mut wait_object std ptr null_mut ( ) let ret unsafe { RegisterWaitForSingleObject ( mut wait_object child as_raw_handle ( ) as HANDLE Some ( callback ) std ptr null_mut ( ) INFINITE WT_EXECUTEINWAITTHREAD WT_EXECUTEONLYONCE ) } if ret 0 { return Err ( io Error last_os_error ( ) ) } // Waits for the next SIGCHLD signal. fn wait_sigchld ( ) { CALLBACK 1 lock ( ) unwrap ( ) recv ( ) ok ( ) } // Wraps a sync I/O type into an async I/O type. fn wrap T ( io T ) io Result Unblock T { Ok ( Unblock new ( io ) ) } } else if [ cfg ( unix ) ] { static SIGNALS Lazy signal_hook iterator Signals Lazy new ( { signal_hook iterator Signals new ( [ signal_hook SIGCHLD ] ) expect ( " " ) } ) // Make sure the signal handler is registered before interacting with the process. Lazy force ( SIGNALS ) // Waits for the next SIGCHLD signal. fn wait_sigchld ( ) { SIGNALS forever ( ) next ( ) } // Wraps a sync I/O type into an async I/O type. fn wrap T std os unix io AsRawFd ( io T ) io Result Async T { Async new ( io ) } } } static ZOMBIES : Lazy < Mutex < Vec < std :: process :: Child > > > = Lazy :: new ( | | { // Start a thread that handles SIGCHLD and notifies tasks when child processes exit. thread :: Builder :: new ( ) . name ( " " . to_string ( ) ) . spawn ( move | | { loop { // Wait for the next SIGCHLD signal. wait_sigchld ( ) ; // Notify all listeners waiting on the SIGCHLD event. SIGCHLD . notify ( std :: usize :: MAX ) ; // Reap zombie processes. let mut zombies = ZOMBIES . lock ( ) . unwrap ( ) ; let mut i = 0 ; while i < zombies . len ( ) { if let Ok ( None ) = zombies [ i ] . try_wait ( ) { i += 1 ; } else { zombies . swap_remove ( i ) ; } } } } ) . expect ( " " ) ; Mutex :: new ( Vec :: new ( ) ) } ) ; // Make sure the thread is started. Lazy :: force ( & ZOMBIES ) ; // When the last reference to the child process is dropped, push it into the zombie list. impl Drop for ChildGuard { fn drop ( & mut self ) { if self . reap_on_drop { let mut zombies = ZOMBIES . lock ( ) . unwrap ( ) ; if let Ok ( None ) = self . get_mut ( ) . try_wait ( ) { zombies . push ( self . inner . take ( ) . unwrap ( ) ) ; } } } } Ok ( Child { stdin , stdout , stderr , child : Arc :: new ( Mutex :: new ( ChildGuard { inner : Some ( child ) , reap_on_drop : cmd . reap_on_drop , } ) ) , kill_on_drop : cmd . kill_on_drop , } ) }
Wraps the inner child process handle and registers it in the global process list.
Wraps the inner child process handle and registers it in the global process list .
cmd
&mut Command
cmd
&mut Command