From ad1b4f3b2bc106760c950f961e98f913cf117e88 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Sat, 14 Oct 2017 21:25:56 -0400 Subject: [PATCH] Optimize grouping for *nix archs --- Cargo.lock | 1 + Cargo.toml | 3 ++ src/exec/ticket.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 2 ++ 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc5935b..811623c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ dependencies = [ "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 156448f..44b46ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,9 @@ num_cpus = "1.6.2" regex = "0.2" regex-syntax = "0.4" +[target.'cfg(all(unix, not(target_os = "redox")))'.dependencies] +libc = "0.2" + [dev-dependencies] diff = "0.1" tempdir = "0.3" diff --git a/src/exec/ticket.rs b/src/exec/ticket.rs index 5a2ca9e..475daca 100644 --- a/src/exec/ticket.rs +++ b/src/exec/ticket.rs @@ -1,7 +1,7 @@ use std::env; -use std::process::{Command, Stdio}; +use std::process::Command; use std::sync::{Arc, Mutex}; -use std::io::{self, Write}; +use std::io; lazy_static! { /// On non-Windows systems, the `SHELL` environment variable will be used to determine the @@ -29,8 +29,12 @@ impl<'a> CommandTicket<'a> { } /// Executes the command stored within the ticket, and - /// clearing the command's buffer when finished. + /// clearing the command's buffer when finished.' + #[cfg(not(all(unix, not(target_os = "redox"))))] pub fn then_execute(self) { + use std::process::Stdio; + use std::io::Write; + // Spawn a shell with the supplied command. let cmd = Command::new(COMMAND.0.as_str()) .arg(COMMAND.1) @@ -58,4 +62,67 @@ impl<'a> CommandTicket<'a> { // Clear the buffer for later re-use. self.command.clear(); } + + #[cfg(all(unix, not(target_os = "redox")))] + pub fn then_execute(self) { + use libc::*; + use std::fs::File; + use std::os::unix::process::CommandExt; + use std::os::unix::io::FromRawFd; + + // Initial a pair of pipes that will be used to + // pipe the std{out,err} of the spawned process. + let mut stdout_fds = [0; 2]; + let mut stderr_fds = [0; 2]; + + unsafe { + pipe(stdout_fds.as_mut_ptr()); + pipe(stderr_fds.as_mut_ptr()); + } + + // Spawn a shell with the supplied command. + let cmd = Command::new(COMMAND.0.as_str()) + .arg(COMMAND.1) + .arg(&self.command) + .before_exec(move || unsafe { + // Configure the pipes accordingly in the child. + dup2(stdout_fds[1], STDOUT_FILENO); + dup2(stderr_fds[1], STDERR_FILENO); + close(stdout_fds[0]); + close(stdout_fds[1]); + close(stderr_fds[0]); + close(stderr_fds[1]); + Ok(()) + }) + .spawn(); + + // Open the read end of the pipes as `File`s. + let (mut pout, mut perr) = unsafe { + close(stdout_fds[1]); + close(stderr_fds[1]); + ( + File::from_raw_fd(stdout_fds[0]), + File::from_raw_fd(stderr_fds[0]), + ) + }; + + match cmd { + Ok(mut child) => { + let _ = child.wait(); + + // Create a lock to ensure that this thread has exclusive access to writing. + let _lock = self.out_perm.lock().unwrap(); + + // And then write the outputs of the process until EOF is sent to each file. + let stdout = io::stdout(); + let stderr = io::stderr(); + let _ = io::copy(&mut pout, &mut stdout.lock()); + let _ = io::copy(&mut perr, &mut stderr.lock()); + } + Err(why) => eprintln!("fd: exec error: {}", why), + } + + // Clear the command string's buffer for later re-use. + self.command.clear(); + } } diff --git a/src/main.rs b/src/main.rs index d52b856..d7574fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ extern crate clap; extern crate ignore; #[macro_use] extern crate lazy_static; +#[cfg(all(unix, not(target_os = "redox")))] +extern crate libc; extern crate num_cpus; extern crate regex; extern crate regex_syntax;