about summary refs log tree commit diff
path: root/src/libstd/sys/unix/process/process_unix.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-01-25 18:13:45 -0800
committerBryan Drewery <bryan@shatow.net>2018-02-28 15:35:59 -0800
commit11696acd6d070a90e8dd386a3c9ae877740fb0e2 (patch)
treefac451ab1ffac7194a6969ed0a630f28f10bd6cb /src/libstd/sys/unix/process/process_unix.rs
parent518b3f7eeed94027673b55b6f459a22983ac542f (diff)
downloadrust-11696acd6d070a90e8dd386a3c9ae877740fb0e2.tar.gz
rust-11696acd6d070a90e8dd386a3c9ae877740fb0e2.zip
Support posix_spawn() when possible.
Diffstat (limited to 'src/libstd/sys/unix/process/process_unix.rs')
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index 189280a4ba9..d66c2375140 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -24,6 +24,7 @@ impl Command {
                  -> io::Result<(Process, StdioPipes)> {
         use sys;
 
+
         const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
 
         let envp = self.capture_env();
@@ -34,6 +35,11 @@ impl Command {
         }
 
         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+
+        if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
+            return Ok((ret, ours))
+        }
+
         let (input, output) = sys::pipe::anon_pipe()?;
 
         let pid = unsafe {
@@ -229,6 +235,102 @@ impl Command {
         libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
         io::Error::last_os_error()
     }
+
+    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+    fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
+        -> io::Result<Option<Process>>
+    {
+        Ok(None)
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "macos"))]
+    fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>)
+        -> io::Result<Option<Process>>
+    {
+        use mem;
+        use sys;
+
+        if self.get_cwd().is_some() ||
+            self.get_gid().is_some() ||
+            self.get_uid().is_some() ||
+            self.get_closures().len() != 0 {
+            return Ok(None)
+        }
+
+        let mut p = Process { pid: 0, status: None };
+
+        struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);
+
+        impl Drop for PosixSpawnFileActions {
+            fn drop(&mut self) {
+                unsafe {
+                    libc::posix_spawn_file_actions_destroy(&mut self.0);
+                }
+            }
+        }
+
+        struct PosixSpawnattr(libc::posix_spawnattr_t);
+
+        impl Drop for PosixSpawnattr {
+            fn drop(&mut self) {
+                unsafe {
+                    libc::posix_spawnattr_destroy(&mut self.0);
+                }
+            }
+        }
+
+        unsafe {
+            let mut file_actions = PosixSpawnFileActions(mem::zeroed());
+            let mut attrs = PosixSpawnattr(mem::zeroed());
+
+            libc::posix_spawnattr_init(&mut attrs.0);
+            libc::posix_spawn_file_actions_init(&mut file_actions.0);
+
+            if let Some(fd) = stdio.stdin.fd() {
+                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+                                                           fd,
+                                                           libc::STDIN_FILENO))?;
+            }
+            if let Some(fd) = stdio.stdout.fd() {
+                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+                                                           fd,
+                                                           libc::STDOUT_FILENO))?;
+            }
+            if let Some(fd) = stdio.stderr.fd() {
+                cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0,
+                                                           fd,
+                                                           libc::STDERR_FILENO))?;
+            }
+
+            let mut set: libc::sigset_t = mem::zeroed();
+            cvt(libc::sigemptyset(&mut set))?;
+            cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0,
+                                                 &set))?;
+            cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?;
+            cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0,
+                                                    &set))?;
+
+            let flags = libc::POSIX_SPAWN_SETSIGDEF |
+                libc::POSIX_SPAWN_SETSIGMASK;
+            cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?;
+
+            let envp = envp.map(|c| c.as_ptr())
+                .unwrap_or(sys::os::environ() as *const _);
+            let ret = libc::posix_spawnp(
+                &mut p.pid,
+                self.get_argv()[0],
+                &file_actions.0,
+                &attrs.0,
+                self.get_argv().as_ptr() as *const _,
+                envp as *const _,
+            );
+            if ret == 0 {
+                Ok(Some(p))
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////