aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid LeGare <legare@google.com>2022-03-03 02:20:55 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-03 02:20:55 +0000
commit0ea93d7d7c90197ee82b42cbdf27c5fbfe2c5ff3 (patch)
treefa75cb911f3976cb5994a09764373f0edd644abb
parentbfc892909c6dbec1c8e3f1e95ba1afeeb2c444b5 (diff)
parente53f7d4621501f8ffc32237d2599b9bb94709c33 (diff)
downloadshared_child-android13-qpr3-c-s3-release.tar.gz
Update shared_child to 1.0.0 am: 384a131edc am: 1a1ad39a5a am: e53f7d4621t_frc_odp_330442040t_frc_odp_330442000t_frc_ase_330444010android-13.0.0_r83android-13.0.0_r82android-13.0.0_r81android-13.0.0_r80android-13.0.0_r79android-13.0.0_r78android-13.0.0_r77android-13.0.0_r76android-13.0.0_r75android-13.0.0_r74android-13.0.0_r73android-13.0.0_r72android-13.0.0_r71android-13.0.0_r70android-13.0.0_r69android-13.0.0_r68android-13.0.0_r67android-13.0.0_r66android-13.0.0_r65android-13.0.0_r64android-13.0.0_r63android-13.0.0_r62android-13.0.0_r61android-13.0.0_r60android-13.0.0_r59android-13.0.0_r58android-13.0.0_r57android-13.0.0_r56android-13.0.0_r55android-13.0.0_r54android-13.0.0_r53android-13.0.0_r52android-13.0.0_r51android-13.0.0_r50android-13.0.0_r49android-13.0.0_r48android-13.0.0_r47android-13.0.0_r46android-13.0.0_r45android-13.0.0_r44android-13.0.0_r43android-13.0.0_r42android-13.0.0_r41android-13.0.0_r40android-13.0.0_r39android-13.0.0_r38android-13.0.0_r37android-13.0.0_r36android-13.0.0_r35android-13.0.0_r34android-13.0.0_r33android-13.0.0_r32android-13.0.0_r30android-13.0.0_r29android-13.0.0_r28android-13.0.0_r27android-13.0.0_r24android-13.0.0_r23android-13.0.0_r22android-13.0.0_r21android-13.0.0_r20android-13.0.0_r19android-13.0.0_r18android-13.0.0_r17android-13.0.0_r16aml_go_odp_330912000aml_go_ads_330915100aml_go_ads_330915000aml_go_ads_330913000android13-qpr3-s9-releaseandroid13-qpr3-s8-releaseandroid13-qpr3-s7-releaseandroid13-qpr3-s6-releaseandroid13-qpr3-s5-releaseandroid13-qpr3-s4-releaseandroid13-qpr3-s3-releaseandroid13-qpr3-s2-releaseandroid13-qpr3-s14-releaseandroid13-qpr3-s13-releaseandroid13-qpr3-s12-releaseandroid13-qpr3-s11-releaseandroid13-qpr3-s10-releaseandroid13-qpr3-s1-releaseandroid13-qpr3-releaseandroid13-qpr3-c-s8-releaseandroid13-qpr3-c-s7-releaseandroid13-qpr3-c-s6-releaseandroid13-qpr3-c-s5-releaseandroid13-qpr3-c-s4-releaseandroid13-qpr3-c-s3-releaseandroid13-qpr3-c-s2-releaseandroid13-qpr3-c-s12-releaseandroid13-qpr3-c-s11-releaseandroid13-qpr3-c-s10-releaseandroid13-qpr3-c-s1-releaseandroid13-qpr2-s9-releaseandroid13-qpr2-s8-releaseandroid13-qpr2-s7-releaseandroid13-qpr2-s6-releaseandroid13-qpr2-s5-releaseandroid13-qpr2-s3-releaseandroid13-qpr2-s2-releaseandroid13-qpr2-s12-releaseandroid13-qpr2-s11-releaseandroid13-qpr2-s10-releaseandroid13-qpr2-s1-releaseandroid13-qpr2-releaseandroid13-qpr2-b-s1-releaseandroid13-qpr1-s8-releaseandroid13-qpr1-s7-releaseandroid13-qpr1-s6-releaseandroid13-qpr1-s5-releaseandroid13-qpr1-s4-releaseandroid13-qpr1-s3-releaseandroid13-qpr1-s2-releaseandroid13-qpr1-s1-releaseandroid13-qpr1-releaseandroid13-mainline-go-adservices-releaseandroid13-frc-odp-releaseandroid13-devandroid13-d4-s2-releaseandroid13-d4-s1-releaseandroid13-d4-releaseandroid13-d3-s1-releaseandroid13-d2-release
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/shared_child/+/2005937 Change-Id: Ic4a38b1195da86e9f527ddfac146e120e55a41ae
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml31
-rw-r--r--.travis.yml8
-rw-r--r--Android.bp4
-rw-r--r--Cargo.toml11
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA10
-rw-r--r--README.md2
-rw-r--r--README.tpl2
-rw-r--r--appveyor.yml32
-rw-r--r--src/lib.rs140
-rw-r--r--src/sys/unix.rs3
12 files changed, 175 insertions, 72 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index a082427..ea16222 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "9ff8c8e9d6dc8da25a7f7947f4488ceecdffa553"
+ "sha1": "ed1c4f6eed646608390a4130bb6de78d630a7b0f"
}
}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..8a05d56
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,31 @@
+name: tests
+
+on:
+ push:
+ branches:
+ - "*"
+ # not on tags
+ pull_request:
+
+env:
+ RUSTFLAGS: "-D warnings"
+ RUST_BACKTRACE: "1"
+
+jobs:
+ cargo_tests:
+ name: ${{ matrix.os }} ${{ matrix.rust_channel }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
+ rust_channel: [stable, beta, nightly]
+
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust_channel }}
+ profile: minimal
+ override: true
+ - run: cargo test
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 0d4ad53..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-language: rust
-os:
- - linux
- - osx
-rust:
- - stable
- - beta
- - nightly
diff --git a/Android.bp b/Android.bp
index 02272a3..60a4abd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,7 @@ rust_library {
host_supported: true,
crate_name: "shared_child",
cargo_env_compat: true,
- cargo_pkg_version: "0.3.5",
+ cargo_pkg_version: "1.0.0",
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
@@ -41,7 +41,7 @@ rust_test {
host_supported: true,
crate_name: "shared_child",
cargo_env_compat: true,
- cargo_pkg_version: "0.3.5",
+ cargo_pkg_version: "1.0.0",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
diff --git a/Cargo.toml b/Cargo.toml
index 75e890b..d13367c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,17 +3,16 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "shared_child"
-version = "0.3.5"
+version = "1.0.0"
authors = ["jacko"]
description = "a library for using child processes from multiple threads"
documentation = "https://docs.rs/shared_child"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 5c8ea27..2453bc6 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "shared_child"
-version = "0.3.5"
+version = "1.0.0"
authors = ["jacko"]
license = "MIT"
repository = "https://github.com/oconnor663/shared_child.rs"
diff --git a/METADATA b/METADATA
index 2c67826..029d963 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/shared_child/shared_child-0.3.5.crate"
+ value: "https://static.crates.io/crates/shared_child/shared_child-1.0.0.crate"
}
- version: "0.3.5"
+ version: "1.0.0"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 4
- day: 13
+ year: 2022
+ month: 3
+ day: 1
}
}
diff --git a/README.md b/README.md
index 94525fa..b08106d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# shared_child.rs [![Travis build](https://travis-ci.org/oconnor663/shared_child.rs.svg?branch=master)](https://travis-ci.org/oconnor663/shared_child.rs) [![Build status](https://ci.appveyor.com/api/projects/status/900ckow3c5awq3t5/branch/master?svg=true)](https://ci.appveyor.com/project/oconnor663/shared-child-rs/branch/master) [![crates.io](https://img.shields.io/crates/v/shared_child.svg)](https://crates.io/crates/shared_child) [![docs.rs](https://docs.rs/shared_child/badge.svg)](https://docs.rs/shared_child)
+# shared_child.rs [![Actions Status](https://github.com/oconnor663/shared_child.rs/workflows/tests/badge.svg)](https://github.com/oconnor663/shared_child.rs/actions) [![crates.io](https://img.shields.io/crates/v/shared_child.svg)](https://crates.io/crates/shared_child) [![docs.rs](https://docs.rs/shared_child/badge.svg)](https://docs.rs/shared_child)
A library for awaiting and killing child processes from multiple threads.
diff --git a/README.tpl b/README.tpl
index 3ad7e39..c16ee7f 100644
--- a/README.tpl
+++ b/README.tpl
@@ -1,3 +1,3 @@
-# {{crate}}.rs [![Travis build](https://travis-ci.org/oconnor663/shared_child.rs.svg?branch=master)](https://travis-ci.org/oconnor663/shared_child.rs) [![Build status](https://ci.appveyor.com/api/projects/status/900ckow3c5awq3t5/branch/master?svg=true)](https://ci.appveyor.com/project/oconnor663/shared-child-rs/branch/master) [![crates.io](https://img.shields.io/crates/v/shared_child.svg)](https://crates.io/crates/shared_child) [![docs.rs](https://docs.rs/shared_child/badge.svg)](https://docs.rs/shared_child)
+# {{crate}}.rs [![Actions Status](https://github.com/oconnor663/shared_child.rs/workflows/tests/badge.svg)](https://github.com/oconnor663/shared_child.rs/actions) [![crates.io](https://img.shields.io/crates/v/shared_child.svg)](https://crates.io/crates/shared_child) [![docs.rs](https://docs.rs/shared_child/badge.svg)](https://docs.rs/shared_child)
{{readme}}
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 354716e..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-environment:
- matrix:
- - TARGET: x86_64-pc-windows-msvc
- VERSION: 1.31.0
- - TARGET: i686-pc-windows-msvc
- VERSION: 1.31.0
- - TARGET: i686-pc-windows-gnu
- VERSION: 1.31.0
- - TARGET: x86_64-pc-windows-msvc
- VERSION: beta
- - TARGET: i686-pc-windows-msvc
- VERSION: beta
- - TARGET: i686-pc-windows-gnu
- VERSION: beta
- - TARGET: x86_64-pc-windows-msvc
- VERSION: nightly
- - TARGET: i686-pc-windows-msvc
- VERSION: nightly
- - TARGET: i686-pc-windows-gnu
- VERSION: nightly
-install:
- - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:VERSION}-${env:TARGET}.exe"
- - rust-%VERSION%-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- - SET PATH=%PATH%;C:\MinGW\bin
- - rustc -V
- - cargo -V
-
-build: false
-
-test_script:
- - cargo test --verbose
diff --git a/src/lib.rs b/src/lib.rs
index 58c1e0c..5c4f200 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -62,7 +62,7 @@
//! ```
use std::io;
-use std::process::{Child, Command, ExitStatus};
+use std::process::{Child, ChildStderr, ChildStdin, ChildStdout, Command, ExitStatus};
use std::sync::{Condvar, Mutex};
mod sys;
@@ -85,16 +85,36 @@ pub struct SharedChild {
}
impl SharedChild {
- /// Spawn a new `SharedChild` from a `std::process::Command`.
- pub fn spawn(command: &mut Command) -> io::Result<SharedChild> {
+ /// Spawn a new `SharedChild` from a
+ /// [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html).
+ pub fn spawn(command: &mut Command) -> io::Result<Self> {
let child = command.spawn()?;
- Ok(SharedChild {
+ Ok(Self {
child: Mutex::new(child),
state_lock: Mutex::new(NotWaiting),
state_condvar: Condvar::new(),
})
}
+ /// Construct a new `SharedChild` from an already spawned
+ /// [`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html).
+ ///
+ /// This constructor needs to know whether `child` has already been waited on, and the only way
+ /// to find that out is to call `child.try_wait()` internally. If the child process is
+ /// currently a zombie, that call will clean it up as a side effect. The [`SharedChild::spawn`]
+ /// constructor doesn't need to do this.
+ pub fn new(mut child: Child) -> io::Result<Self> {
+ let state = match child.try_wait()? {
+ Some(status) => Exited(status),
+ None => NotWaiting,
+ };
+ Ok(Self {
+ child: Mutex::new(child),
+ state_lock: Mutex::new(state),
+ state_condvar: Condvar::new(),
+ })
+ }
+
/// Return the child process ID.
pub fn id(&self) -> u32 {
self.child.lock().unwrap().id()
@@ -204,15 +224,46 @@ impl SharedChild {
self.child.lock().unwrap().kill()
}
- /// Consume the `SharedChild` and return the `std::process::Child` it
- /// contains.
+ /// Consume the `SharedChild` and return the
+ /// [`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html)
+ /// it contains.
///
- /// We never reap the child process except through `Child::wait`, so the
- /// child object's inner state is correct, even if it was waited on while it
- /// was shared.
+ /// We never reap the child process except by calling `wait` or `try_wait`
+ /// on it, so the child object's inner state is correct, even if it was
+ /// waited on while it was shared.
pub fn into_inner(self) -> Child {
self.child.into_inner().unwrap()
}
+
+ /// Take the child's
+ /// [`stdin`](https://doc.rust-lang.org/std/process/struct.Child.html#structfield.stdin)
+ /// handle, if any.
+ ///
+ /// This will only return `Some` the first time it's called, and then only if the `Command`
+ /// that created the child was configured with `.stdin(Stdio::piped())`.
+ pub fn take_stdin(&self) -> Option<ChildStdin> {
+ self.child.lock().unwrap().stdin.take()
+ }
+
+ /// Take the child's
+ /// [`stdout`](https://doc.rust-lang.org/std/process/struct.Child.html#structfield.stdout)
+ /// handle, if any.
+ ///
+ /// This will only return `Some` the first time it's called, and then only if the `Command`
+ /// that created the child was configured with `.stdout(Stdio::piped())`.
+ pub fn take_stdout(&self) -> Option<ChildStdout> {
+ self.child.lock().unwrap().stdout.take()
+ }
+
+ /// Take the child's
+ /// [`stderr`](https://doc.rust-lang.org/std/process/struct.Child.html#structfield.stderr)
+ /// handle, if any.
+ ///
+ /// This will only return `Some` the first time it's called, and then only if the `Command`
+ /// that created the child was configured with `.stderr(Stdio::piped())`.
+ pub fn take_stderr(&self) -> Option<ChildStderr> {
+ self.child.lock().unwrap().stderr.take()
+ }
}
#[derive(Debug)]
@@ -226,9 +277,9 @@ use crate::ChildState::*;
#[cfg(test)]
mod tests {
- use super::{sys, SharedChild};
- use std;
- use std::process::Command;
+ use super::*;
+ use std::error::Error;
+ use std::process::{Command, Stdio};
use std::sync::Arc;
// Python isn't available on some Unix platforms, e.g. Android, so we need this instead.
@@ -244,6 +295,7 @@ mod tests {
cmd
}
+ // Python isn't available on some Unix platforms, e.g. Android, so we need this instead.
#[cfg(unix)]
pub fn sleep_forever_cmd() -> Command {
let mut cmd = Command::new("sleep");
@@ -258,6 +310,19 @@ mod tests {
cmd
}
+ // Python isn't available on some Unix platforms, e.g. Android, so we need this instead.
+ #[cfg(unix)]
+ pub fn cat_cmd() -> Command {
+ Command::new("cat")
+ }
+
+ #[cfg(not(unix))]
+ pub fn cat_cmd() -> Command {
+ let mut cmd = Command::new("python");
+ cmd.arg("-c").arg("");
+ cmd
+ }
+
#[test]
fn test_wait() {
let child = SharedChild::spawn(&mut true_cmd()).unwrap();
@@ -345,4 +410,55 @@ mod tests {
// But wait should succeed.
child.wait().unwrap();
}
+
+ #[test]
+ fn test_new() -> Result<(), Box<dyn Error>> {
+ // Spawn a short-lived child.
+ let mut command = cat_cmd();
+ command.stdin(Stdio::piped());
+ command.stdout(Stdio::null());
+ let mut child = command.spawn()?;
+ let child_stdin = child.stdin.take().unwrap();
+
+ // Construct a SharedChild from the Child, which has not yet been waited on. The child is
+ // blocked on stdin, so we know it hasn't yet exited.
+ let mut shared_child = SharedChild::new(child).unwrap();
+ assert!(matches!(
+ *shared_child.state_lock.lock().unwrap(),
+ NotWaiting,
+ ));
+
+ // Now close the child's stdin. This will cause the child to exit.
+ drop(child_stdin);
+
+ // Construct more SharedChild objects from the same child, in a loop. Eventually one of
+ // them will notice that the child has exited.
+ loop {
+ shared_child = SharedChild::new(shared_child.into_inner())?;
+ if let Exited(status) = &*shared_child.state_lock.lock().unwrap() {
+ assert!(status.success());
+ return Ok(());
+ }
+ }
+ }
+
+ #[test]
+ fn test_takes() -> Result<(), Box<dyn Error>> {
+ let mut command = true_cmd();
+ command.stdin(Stdio::piped());
+ command.stdout(Stdio::piped());
+ command.stderr(Stdio::piped());
+ let shared_child = SharedChild::spawn(&mut command)?;
+
+ assert!(shared_child.take_stdin().is_some());
+ assert!(shared_child.take_stdout().is_some());
+ assert!(shared_child.take_stderr().is_some());
+
+ assert!(shared_child.take_stdin().is_none());
+ assert!(shared_child.take_stdout().is_none());
+ assert!(shared_child.take_stderr().is_none());
+
+ shared_child.wait()?;
+ Ok(())
+ }
}
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index 400f910..abdfa48 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -48,9 +48,6 @@ pub fn try_wait_without_reaping(handle: Handle) -> io::Result<bool> {
// invocation, then check for a non-zero value afterwards.
//
// https://github.com/opensource-apple/xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_exit.c#L2150-L2156
- //
- // XXX: The siginfo_t struct has padding. Does that make it unsound to
- // initialize it this way?
siginfo = std::mem::zeroed();
libc::waitid(
libc::P_PID,