aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md64
1 files changed, 64 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..94525fa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,64 @@
+# 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)
+
+A library for awaiting and killing child processes from multiple threads.
+
+- [Docs](https://docs.rs/shared_child)
+- [Crate](https://crates.io/crates/shared_child)
+- [Repo](https://github.com/oconnor663/shared_child.rs)
+
+The
+[`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html)
+type in the standard library provides
+[`wait`](https://doc.rust-lang.org/std/process/struct.Child.html#method.wait)
+and
+[`kill`](https://doc.rust-lang.org/std/process/struct.Child.html#method.kill)
+methods that take `&mut self`, making it impossible to kill a child process
+while another thread is waiting on it. That design works around a race
+condition in Unix's `waitpid` function, where a PID might get reused as soon
+as the wait returns, so a signal sent around the same time could
+accidentally get delivered to the wrong process.
+
+However with the newer POSIX `waitid` function, we can wait on a child
+without freeing its PID for reuse. That makes it safe to send signals
+concurrently. Windows has actually always supported this, by preventing PID
+reuse while there are still open handles to a child process. This library
+wraps `std::process::Child` for concurrent use, backed by these APIs.
+
+Compatibility note: The `libc` crate doesn't currently support `waitid` on
+NetBSD or OpenBSD, or on older versions of OSX. There [might also
+be](https://bugs.python.org/msg167016) some version of OSX where the
+`waitid` function exists but is broken. We can add a "best effort"
+workaround using `waitpid` for these platforms as we run into them. Please
+[file an issue](https://github.com/oconnor663/shared_child.rs/issues/new) if
+you hit this.
+
+## Example
+
+```rust
+use shared_child::SharedChild;
+use std::process::Command;
+use std::sync::Arc;
+
+// Spawn a child that will just sleep for a long time,
+// and put it in an Arc to share between threads.
+let mut command = Command::new("python");
+command.arg("-c").arg("import time; time.sleep(1000000000)");
+let shared_child = SharedChild::spawn(&mut command).unwrap();
+let child_arc = Arc::new(shared_child);
+
+// On another thread, wait on the child process.
+let child_arc_clone = child_arc.clone();
+let thread = std::thread::spawn(move || {
+ child_arc_clone.wait().unwrap()
+});
+
+// While the other thread is waiting, kill the child process.
+// This wouldn't be possible with e.g. Arc<Mutex<Child>> from
+// the standard library, because the waiting thread would be
+// holding the mutex.
+child_arc.kill().unwrap();
+
+// Join the waiting thread and get the exit status.
+let exit_status = thread.join().unwrap();
+assert!(!exit_status.success());
+```