summaryrefslogtreecommitdiffstats
path: root/vendor/wait-timeout
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/wait-timeout')
-rw-r--r--vendor/wait-timeout/.cargo-checksum.json1
-rw-r--r--vendor/wait-timeout/Cargo.toml30
-rw-r--r--vendor/wait-timeout/LICENSE-APACHE201
-rw-r--r--vendor/wait-timeout/LICENSE-MIT25
-rw-r--r--vendor/wait-timeout/README.md14
-rw-r--r--vendor/wait-timeout/appveyor.yml17
-rw-r--r--vendor/wait-timeout/src/bin/exit.rs4
-rw-r--r--vendor/wait-timeout/src/bin/reader.rs7
-rw-r--r--vendor/wait-timeout/src/bin/sleep.rs4
-rw-r--r--vendor/wait-timeout/src/lib.rs68
-rw-r--r--vendor/wait-timeout/src/unix.rs305
-rw-r--r--vendor/wait-timeout/src/windows.rs34
-rw-r--r--vendor/wait-timeout/tests/smoke.rs103
13 files changed, 813 insertions, 0 deletions
diff --git a/vendor/wait-timeout/.cargo-checksum.json b/vendor/wait-timeout/.cargo-checksum.json
new file mode 100644
index 000000000..ef56f7846
--- /dev/null
+++ b/vendor/wait-timeout/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"bc22efbfab1ed89ef7321da03f0e13072232a8e7af6c4d19f917c85d46775fda","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"defee9f062a15d08783c2f6ba6b5cdf7bb8231e1388639b25e6bcc56c02db319","appveyor.yml":"3a74394c3e3ef3b2c7d9458f526e47587977e98d026b63f00be29479075ff597","src/bin/exit.rs":"6361e1d6b0aa6b3c6d01dad168d41ee29f6cb616711ac48a1fef99f87fd989ef","src/bin/reader.rs":"17b5253ac6876d4119595b5fee27506cf9374fcaf896d5e73a8ba7bd2f9500d2","src/bin/sleep.rs":"da1762ba3729657315f2062001a001dd530e14f074917d42a1065019444b0ddd","src/lib.rs":"d5bdf98ce3c3c0ed3cde00883b39245426478151f20b6a8625629df5e4de6e2c","src/unix.rs":"359af52d422a33ff115ab224a8eb7b22d8f921bccde3cf14e503fe10e67dcc9d","src/windows.rs":"ac934e8ed01f46a6aba5ab3627f56123575bfff3425c602dfe54dd52d77a74c1","tests/smoke.rs":"3ce2c4af7efb3e0a651960e69155b13449930200484b2a4f69b3019af5cd76cd"},"package":"9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"} \ No newline at end of file
diff --git a/vendor/wait-timeout/Cargo.toml b/vendor/wait-timeout/Cargo.toml
new file mode 100644
index 000000000..e62830113
--- /dev/null
+++ b/vendor/wait-timeout/Cargo.toml
@@ -0,0 +1,30 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# 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
+#
+# 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)
+
+[package]
+name = "wait-timeout"
+version = "0.2.0"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+description = "A crate to wait on a child process with a timeout specified across Unix and\nWindows platforms.\n"
+homepage = "https://github.com/alexcrichton/wait-timeout"
+documentation = "https://docs.rs/wait-timeout"
+readme = "README.md"
+categories = ["os"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/alexcrichton/wait-timeout"
+[target."cfg(unix)".dependencies.libc]
+version = "0.2"
+[badges.appveyor]
+repository = "alexcrichton/wait-timeout"
+
+[badges.travis-ci]
+repository = "alexcrichton/wait-timeout"
diff --git a/vendor/wait-timeout/LICENSE-APACHE b/vendor/wait-timeout/LICENSE-APACHE
new file mode 100644
index 000000000..16fe87b06
--- /dev/null
+++ b/vendor/wait-timeout/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/wait-timeout/LICENSE-MIT b/vendor/wait-timeout/LICENSE-MIT
new file mode 100644
index 000000000..39e0ed660
--- /dev/null
+++ b/vendor/wait-timeout/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/wait-timeout/README.md b/vendor/wait-timeout/README.md
new file mode 100644
index 000000000..1c10e6f87
--- /dev/null
+++ b/vendor/wait-timeout/README.md
@@ -0,0 +1,14 @@
+# wait-timeout
+
+[![Build Status](https://travis-ci.org/alexcrichton/wait-timeout.svg?branch=master)](https://travis-ci.org/alexcrichton/wait-timeout)
+[![Build status](https://ci.appveyor.com/api/projects/status/3t5mh1c8i4lnolma?svg=true)](https://ci.appveyor.com/project/alexcrichton/wait-timeout)
+
+[Documentation](https://docs.rs/wait-timeout)
+
+Rust crate for waiting on a `Child` process with a timeout specified.
+
+```toml
+# Cargo.toml
+[dependencies]
+wait-timeout = "0.1.5"
+```
diff --git a/vendor/wait-timeout/appveyor.yml b/vendor/wait-timeout/appveyor.yml
new file mode 100644
index 000000000..4a6104291
--- /dev/null
+++ b/vendor/wait-timeout/appveyor.yml
@@ -0,0 +1,17 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: i686-pc-windows-gnu
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+ - rust-nightly-%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 --target %TARGET%
diff --git a/vendor/wait-timeout/src/bin/exit.rs b/vendor/wait-timeout/src/bin/exit.rs
new file mode 100644
index 000000000..f33c49f34
--- /dev/null
+++ b/vendor/wait-timeout/src/bin/exit.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let code = std::env::args().nth(1).unwrap().parse().unwrap();
+ std::process::exit(code);
+}
diff --git a/vendor/wait-timeout/src/bin/reader.rs b/vendor/wait-timeout/src/bin/reader.rs
new file mode 100644
index 000000000..94b017e64
--- /dev/null
+++ b/vendor/wait-timeout/src/bin/reader.rs
@@ -0,0 +1,7 @@
+use std::io::{Read, stdin};
+
+#[allow(unused_must_use)]
+fn main() {
+ let mut buffer: [u8; 32] = Default::default();
+ stdin().read(&mut buffer);
+}
diff --git a/vendor/wait-timeout/src/bin/sleep.rs b/vendor/wait-timeout/src/bin/sleep.rs
new file mode 100644
index 000000000..48dabdc02
--- /dev/null
+++ b/vendor/wait-timeout/src/bin/sleep.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let amt = std::env::args().nth(1).unwrap().parse().unwrap();
+ std::thread::sleep(std::time::Duration::from_millis(amt));
+}
diff --git a/vendor/wait-timeout/src/lib.rs b/vendor/wait-timeout/src/lib.rs
new file mode 100644
index 000000000..7c19bf30a
--- /dev/null
+++ b/vendor/wait-timeout/src/lib.rs
@@ -0,0 +1,68 @@
+//! A crate to wait on a child process with a particular timeout.
+//!
+//! This crate is an implementation for Unix and Windows of the ability to wait
+//! on a child process with a timeout specified. On Windows the implementation
+//! is fairly trivial as it's just a call to `WaitForSingleObject` with a
+//! timeout argument, but on Unix the implementation is much more involved. The
+//! current implementation registers a `SIGCHLD` handler and initializes some
+//! global state. This handler also works within multi-threaded environments.
+//! If your application is otherwise handling `SIGCHLD` then bugs may arise.
+//!
+//! # Example
+//!
+//! ```no_run
+//! use std::process::Command;
+//! use wait_timeout::ChildExt;
+//! use std::time::Duration;
+//!
+//! let mut child = Command::new("foo").spawn().unwrap();
+//!
+//! let one_sec = Duration::from_secs(1);
+//! let status_code = match child.wait_timeout(one_sec).unwrap() {
+//! Some(status) => status.code(),
+//! None => {
+//! // child hasn't exited yet
+//! child.kill().unwrap();
+//! child.wait().unwrap().code()
+//! }
+//! };
+//! ```
+
+#![deny(missing_docs, warnings)]
+#![doc(html_root_url = "https://docs.rs/wait-timeout/0.1")]
+
+#[cfg(unix)]
+extern crate libc;
+
+use std::io;
+use std::process::{Child, ExitStatus};
+use std::time::Duration;
+
+#[cfg(unix)] #[path = "unix.rs"]
+mod imp;
+#[cfg(windows)] #[path = "windows.rs"]
+mod imp;
+
+/// Extension methods for the standard `std::process::Child` type.
+pub trait ChildExt {
+ /// Deprecated, use `wait_timeout` instead.
+ #[doc(hidden)]
+ fn wait_timeout_ms(&mut self, ms: u32) -> io::Result<Option<ExitStatus>> {
+ self.wait_timeout(Duration::from_millis(ms as u64))
+ }
+
+ /// Wait for this child to exit, timing out after the duration `dur` has
+ /// elapsed.
+ ///
+ /// If `Ok(None)` is returned then the timeout period elapsed without the
+ /// child exiting, and if `Ok(Some(..))` is returned then the child exited
+ /// with the specified exit code.
+ fn wait_timeout(&mut self, dur: Duration) -> io::Result<Option<ExitStatus>>;
+}
+
+impl ChildExt for Child {
+ fn wait_timeout(&mut self, dur: Duration) -> io::Result<Option<ExitStatus>> {
+ drop(self.stdin.take());
+ imp::wait_timeout(self, dur)
+ }
+}
diff --git a/vendor/wait-timeout/src/unix.rs b/vendor/wait-timeout/src/unix.rs
new file mode 100644
index 000000000..535855378
--- /dev/null
+++ b/vendor/wait-timeout/src/unix.rs
@@ -0,0 +1,305 @@
+//! Unix implementation of waiting for children with timeouts
+//!
+//! On unix, wait() and its friends have no timeout parameters, so there is
+//! no way to time out a thread in wait(). From some googling and some
+//! thinking, it appears that there are a few ways to handle timeouts in
+//! wait(), but the only real reasonable one for a multi-threaded program is
+//! to listen for SIGCHLD.
+//!
+//! With this in mind, the waiting mechanism with a timeout only uses
+//! waitpid() with WNOHANG, but otherwise all the necessary blocking is done by
+//! waiting for a SIGCHLD to arrive (and that blocking has a timeout). Note,
+//! however, that waitpid() is still used to actually reap the child.
+//!
+//! Signal handling is super tricky in general, and this is no exception. Due
+//! to the async nature of SIGCHLD, we use the self-pipe trick to transmit
+//! data out of the signal handler to the rest of the application.
+
+#![allow(bad_style)]
+
+use std::cmp;
+use std::collections::HashMap;
+use std::io::{self, Write, Read};
+use std::os::unix::net::UnixStream;
+use std::mem;
+use std::os::unix::prelude::*;
+use std::process::{Child, ExitStatus};
+use std::sync::{Once, ONCE_INIT, Mutex};
+use std::time::{Duration, Instant};
+
+use libc::{self, c_int};
+
+static INIT: Once = ONCE_INIT;
+static mut STATE: *mut State = 0 as *mut _;
+
+struct State {
+ prev: libc::sigaction,
+ write: UnixStream,
+ read: UnixStream,
+ map: Mutex<StateMap>,
+}
+
+type StateMap = HashMap<*mut Child, (UnixStream, Option<ExitStatus>)>;
+
+pub fn wait_timeout(child: &mut Child, dur: Duration)
+ -> io::Result<Option<ExitStatus>> {
+ INIT.call_once(State::init);
+ unsafe {
+ (*STATE).wait_timeout(child, dur)
+ }
+}
+
+// Do $value as type_of($target)
+macro_rules! _as {
+ ($value:expr, $target:expr) => (
+ {
+ let mut x = $target;
+ x = $value as _;
+ x
+ }
+ )
+}
+
+impl State {
+ #[allow(unused_assignments)]
+ fn init() {
+ unsafe {
+ // Create our "self pipe" and then set both ends to nonblocking
+ // mode.
+ let (read, write) = UnixStream::pair().unwrap();
+ read.set_nonblocking(true).unwrap();
+ write.set_nonblocking(true).unwrap();
+
+ let mut state = Box::new(State {
+ prev: mem::zeroed(),
+ write: write,
+ read: read,
+ map: Mutex::new(HashMap::new()),
+ });
+
+ // Register our sigchld handler
+ let mut new: libc::sigaction = mem::zeroed();
+ new.sa_sigaction = sigchld_handler as usize;
+
+ // FIXME: remove this workaround when the PR to libc get merged and released
+ //
+ // This is a workaround for the type mismatch in the definition of SA_*
+ // constants for android. See https://github.com/rust-lang/libc/pull/511
+ //
+ let sa_flags = new.sa_flags;
+ new.sa_flags = _as!(libc::SA_NOCLDSTOP, sa_flags) |
+ _as!(libc::SA_RESTART, sa_flags) |
+ _as!(libc::SA_SIGINFO, sa_flags);
+
+ assert_eq!(libc::sigaction(libc::SIGCHLD, &new, &mut state.prev), 0);
+
+ STATE = mem::transmute(state);
+ }
+ }
+
+ fn wait_timeout(&self, child: &mut Child, dur: Duration)
+ -> io::Result<Option<ExitStatus>> {
+ // First up, prep our notification pipe which will tell us when our
+ // child has been reaped (other threads may signal this pipe).
+ let (read, write) = UnixStream::pair()?;
+ read.set_nonblocking(true)?;
+ write.set_nonblocking(true)?;
+
+ // Next, take a lock on the map of children currently waiting. Right
+ // after this, **before** we add ourselves to the map, we check to see
+ // if our child has actually already exited via a `try_wait`. If the
+ // child has exited then we return immediately as we'll never otherwise
+ // receive a SIGCHLD notification.
+ //
+ // If the wait reports the child is still running, however, we add
+ // ourselves to the map and then block in `select` waiting for something
+ // to happen.
+ let mut map = self.map.lock().unwrap();
+ if let Some(status) = child.try_wait()? {
+ return Ok(Some(status))
+ }
+ assert!(map.insert(child, (write, None)).is_none());
+ drop(map);
+
+ // Make sure that no matter what when we exit our pointer is removed
+ // from the map.
+ struct Remove<'a> {
+ state: &'a State,
+ child: &'a mut Child,
+ }
+ impl<'a> Drop for Remove<'a> {
+ fn drop(&mut self) {
+ let mut map = self.state.map.lock().unwrap();
+ drop(map.remove(&(self.child as *mut Child)));
+ }
+ }
+ let remove = Remove { state: self, child };
+
+
+ // Alright, we're guaranteed that we'll eventually get a SIGCHLD due
+ // to our `try_wait` failing, and we're also guaranteed that we'll
+ // get notified about this because we're in the map. Next up wait
+ // for an event.
+ //
+ // Note that this happens in a loop for two reasons; we could
+ // receive EINTR or we could pick up a SIGCHLD for other threads but not
+ // actually be ready oureslves.
+ let start = Instant::now();
+ let mut fds = [
+ libc::pollfd {
+ fd: self.read.as_raw_fd(),
+ events: libc::POLLIN,
+
+ revents: 0,
+ },
+ libc::pollfd {
+ fd: read.as_raw_fd(),
+ events: libc::POLLIN,
+ revents: 0,
+ },
+ ];
+ loop {
+ let elapsed = start.elapsed();
+ if elapsed >= dur {
+ break
+ }
+ let timeout = dur - elapsed;
+ let timeout = timeout.as_secs().checked_mul(1_000)
+ .and_then(|amt| {
+ amt.checked_add(timeout.subsec_nanos() as u64 / 1_000_000)
+ })
+ .unwrap_or(u64::max_value());
+ let timeout = cmp::min(<c_int>::max_value() as u64, timeout) as c_int;
+ let r = unsafe {
+ libc::poll(fds.as_mut_ptr(), 2, timeout)
+ };
+ let timeout = match r {
+ 0 => true,
+ n if n > 0 => false,
+ n => {
+ let err = io::Error::last_os_error();
+ if err.kind() == io::ErrorKind::Interrupted {
+ continue
+ } else {
+ panic!("error in select = {}: {}", n, err)
+ }
+ }
+ };
+
+ // Now that something has happened, we need to process what actually
+ // happened. There's are three reasons we could have woken up:
+ //
+ // 1. The file descriptor in our SIGCHLD handler was written to.
+ // This means that a SIGCHLD was received and we need to poll the
+ // entire list of waiting processes to figure out which ones
+ // actually exited.
+ // 2. Our file descriptor was written to. This means that another
+ // thread reaped our child and listed the exit status in the
+ // local map.
+ // 3. We timed out. This means we need to remove ourselves from the
+ // map and simply carry on.
+ //
+ // In the case that a SIGCHLD signal was received, we do that
+ // processing and keep going. If our fd was written to or a timeout
+ // was received then we break out of the loop and return from this
+ // call.
+ let mut map = self.map.lock().unwrap();
+ if drain(&self.read) {
+ self.process_sigchlds(&mut map);
+ }
+
+ if drain(&read) || timeout {
+ break
+ }
+ }
+
+ let mut map = self.map.lock().unwrap();
+ let (_write, ret) = map.remove(&(remove.child as *mut Child)).unwrap();
+ drop(map);
+ Ok(ret)
+ }
+
+ fn process_sigchlds(&self, map: &mut StateMap) {
+ for (&k, &mut (ref write, ref mut status)) in map {
+ // Already reaped, nothing to do here
+ if status.is_some() {
+ continue
+ }
+
+ *status = unsafe { (*k).try_wait().unwrap() };
+ if status.is_some() {
+ notify(write);
+ }
+ }
+ }
+}
+
+fn drain(mut file: &UnixStream) -> bool {
+ let mut ret = false;
+ let mut buf = [0u8; 16];
+ loop {
+ match file.read(&mut buf) {
+ Ok(0) => return true, // EOF == something happened
+ Ok(..) => ret = true, // data read, but keep draining
+ Err(e) => {
+ if e.kind() == io::ErrorKind::WouldBlock {
+ return ret
+ } else {
+ panic!("bad read: {}", e)
+ }
+ }
+ }
+ }
+}
+
+fn notify(mut file: &UnixStream) {
+ match file.write(&[1]) {
+ Ok(..) => {}
+ Err(e) => {
+ if e.kind() != io::ErrorKind::WouldBlock {
+ panic!("bad error on write fd: {}", e)
+ }
+ }
+ }
+}
+
+// Signal handler for SIGCHLD signals, must be async-signal-safe!
+//
+// This function will write to the writing half of the "self pipe" to wake
+// up the helper thread if it's waiting. Note that this write must be
+// nonblocking because if it blocks and the reader is the thread we
+// interrupted, then we'll deadlock.
+//
+// When writing, if the write returns EWOULDBLOCK then we choose to ignore
+// it. At that point we're guaranteed that there's something in the pipe
+// which will wake up the other end at some point, so we just allow this
+// signal to be coalesced with the pending signals on the pipe.
+#[allow(unused_assignments)]
+extern fn sigchld_handler(signum: c_int,
+ info: *mut libc::siginfo_t,
+ ptr: *mut libc::c_void) {
+ type FnSigaction = extern fn(c_int, *mut libc::siginfo_t, *mut libc::c_void);
+ type FnHandler = extern fn(c_int);
+
+ unsafe {
+ let state = &*STATE;
+ notify(&state.write);
+
+ let fnptr = state.prev.sa_sigaction;
+ if fnptr == 0 {
+ return
+ }
+ // FIXME: remove this workaround when the PR to libc get merged and released
+ //
+ // This is a workaround for the type mismatch in the definition of SA_*
+ // constants for android. See https://github.com/rust-lang/libc/pull/511
+ //
+ if state.prev.sa_flags & _as!(libc::SA_SIGINFO, state.prev.sa_flags) == 0 {
+ let action = mem::transmute::<usize, FnHandler>(fnptr);
+ action(signum)
+ } else {
+ let action = mem::transmute::<usize, FnSigaction>(fnptr);
+ action(signum, info, ptr)
+ }
+ }
+}
diff --git a/vendor/wait-timeout/src/windows.rs b/vendor/wait-timeout/src/windows.rs
new file mode 100644
index 000000000..a3aa10468
--- /dev/null
+++ b/vendor/wait-timeout/src/windows.rs
@@ -0,0 +1,34 @@
+use std::io;
+use std::os::windows::prelude::*;
+use std::process::{Child, ExitStatus};
+use std::time::Duration;
+
+type DWORD = u32;
+type HANDLE = *mut u8;
+
+const WAIT_OBJECT_0: DWORD = 0x00000000;
+const WAIT_TIMEOUT: DWORD = 258;
+
+extern "system" {
+ fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
+}
+
+pub fn wait_timeout(child: &mut Child, dur: Duration)
+ -> io::Result<Option<ExitStatus>> {
+ let ms = dur.as_secs().checked_mul(1000).and_then(|amt| {
+ amt.checked_add((dur.subsec_nanos() / 1_000_000) as u64)
+ }).expect("failed to convert duration to milliseconds");
+ let ms = if ms > (DWORD::max_value() as u64) {
+ DWORD::max_value()
+ } else {
+ ms as DWORD
+ };
+ unsafe {
+ match WaitForSingleObject(child.as_raw_handle() as *mut _, ms) {
+ WAIT_OBJECT_0 => {}
+ WAIT_TIMEOUT => return Ok(None),
+ _ => return Err(io::Error::last_os_error()),
+ }
+ }
+ child.try_wait()
+}
diff --git a/vendor/wait-timeout/tests/smoke.rs b/vendor/wait-timeout/tests/smoke.rs
new file mode 100644
index 000000000..233259b71
--- /dev/null
+++ b/vendor/wait-timeout/tests/smoke.rs
@@ -0,0 +1,103 @@
+extern crate wait_timeout;
+
+use std::env;
+use std::process::{Command, Child, Stdio};
+use std::time::{Duration, Instant};
+
+use wait_timeout::ChildExt;
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {}", stringify!($e), e),
+ })
+}
+
+fn sleeper(ms: u32) -> Child {
+ let mut me = env::current_exe().unwrap();
+ me.pop();
+ if me.ends_with("deps") {
+ me.pop();
+ }
+ me.push("sleep");
+ t!(Command::new(me).arg(ms.to_string()).spawn())
+}
+
+fn exit(code: u32) -> Child {
+ let mut me = env::current_exe().unwrap();
+ me.pop();
+ if me.ends_with("deps") {
+ me.pop();
+ }
+ me.push("exit");
+ t!(Command::new(me).arg(code.to_string()).spawn())
+}
+
+fn reader() -> Child {
+ let mut me = env::current_exe().unwrap();
+ me.pop();
+ if me.ends_with("deps") {
+ me.pop();
+ }
+ me.push("reader");
+ t!(Command::new(me).stdin(Stdio::piped()).spawn())
+}
+
+#[test]
+fn smoke_insta_timeout() {
+ let mut child = sleeper(1_000);
+ assert_eq!(t!(child.wait_timeout_ms(0)), None);
+
+ t!(child.kill());
+ let status = t!(child.wait());
+ assert!(!status.success());
+}
+
+#[test]
+fn smoke_success() {
+ let start = Instant::now();
+ let mut child = sleeper(0);
+ let status = t!(child.wait_timeout_ms(1_000)).expect("should have succeeded");
+ assert!(status.success());
+
+ assert!(start.elapsed() < Duration::from_millis(500));
+}
+
+#[test]
+fn smoke_timeout() {
+ let mut child = sleeper(1_000_000);
+ let start = Instant::now();
+ assert_eq!(t!(child.wait_timeout_ms(100)), None);
+ assert!(start.elapsed() > Duration::from_millis(80));
+
+ t!(child.kill());
+ let status = t!(child.wait());
+ assert!(!status.success());
+}
+
+#[test]
+fn smoke_reader() {
+ let mut child = reader();
+ let dur = Duration::from_millis(100);
+ let status = t!(child.wait_timeout(dur)).unwrap();
+ assert!(status.success());
+}
+
+#[test]
+fn exit_codes() {
+ let mut child = exit(0);
+ let status = t!(child.wait_timeout_ms(1_000)).unwrap();
+ assert_eq!(status.code(), Some(0));
+
+ let mut child = exit(1);
+ let status = t!(child.wait_timeout_ms(1_000)).unwrap();
+ assert_eq!(status.code(), Some(1));
+
+ // check STILL_ACTIVE on windows, on unix this ends up just getting
+ // truncated so don't bother with it.
+ if cfg!(windows) {
+ let mut child = exit(259);
+ let status = t!(child.wait_timeout_ms(1_000)).unwrap();
+ assert_eq!(status.code(), Some(259));
+ }
+}