summaryrefslogtreecommitdiffstats
path: root/vendor/jobserver
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/jobserver')
-rw-r--r--vendor/jobserver/.cargo-checksum.json2
-rw-r--r--vendor/jobserver/Cargo.toml22
-rw-r--r--vendor/jobserver/src/lib.rs54
-rw-r--r--vendor/jobserver/src/unix.rs122
-rw-r--r--vendor/jobserver/src/wasm.rs5
-rw-r--r--vendor/jobserver/src/windows.rs20
-rw-r--r--vendor/jobserver/tests/client.rs3
-rw-r--r--vendor/jobserver/tests/make-as-a-client.rs3
-rw-r--r--vendor/jobserver/tests/server.rs29
9 files changed, 223 insertions, 37 deletions
diff --git a/vendor/jobserver/.cargo-checksum.json b/vendor/jobserver/.cargo-checksum.json
index 09c948a8e..734fd6db9 100644
--- a/vendor/jobserver/.cargo-checksum.json
+++ b/vendor/jobserver/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"9d5e9bc3aa927124431914287d2830ff03ca5a80931a3b44b3f057b92d09e850","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"07d8d79f8f6b6a94321fe8db78d26ed409de47cee49290947bd6bbfa29d05e9c","src/lib.rs":"891d9c9cf2d75eee30c02ffa8ae7fa8fb1f7675dccddb0cc79a067e1a87a9850","src/unix.rs":"5802f031e80295c5498a2ddb95b5ee6e39b7294f25b35075302fb978b8d4c409","src/wasm.rs":"bb67f97bccd0b0c1762917de342d721e319a3a204604ab1517285c59b5e2a369","src/windows.rs":"f886175abbf75ff45ea3fc09396bbcc3048e7daf732ed78149377f7b8e9148b2","tests/client-of-myself.rs":"ca09bf398f69df4bac1730999e954dbbc3faf3c6512678c136e0938e7e9cd0ab","tests/client.rs":"64547b780edce5ebcd397db1160fd86baab030c530c6976fa013bca9f07a85ff","tests/helper.rs":"c0e6c00eaf849295d8ec23e374690b6645c0f7d993e91abf7ad53ac960f71762","tests/make-as-a-client.rs":"ec09a7cdbf78d6c3b16f26de15766c4bd62d44a913ada6b86b66e067e6c484ba","tests/server.rs":"9a260f1302ae4908479df0bd34b46edb9d2b8b9b3dbc3e2b6666296d9e1b2b84"},"package":"af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"} \ No newline at end of file
+{"files":{"Cargo.toml":"0f712c94e98313fc5833521e1dc0c42a57e5603ea54d1e05a004b95b52fb39b7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"07d8d79f8f6b6a94321fe8db78d26ed409de47cee49290947bd6bbfa29d05e9c","src/lib.rs":"be789fda33a51375fcc87e4bf9bf1256930d718f698f700bbec5e335c83e0659","src/unix.rs":"1e1efc5cd1f381fea83bdaaee474ad3530b396305a9bbdc9da08b0c36baced31","src/wasm.rs":"65d3d8ed45972b4459581505906481d32a50d2f7514cd7ff2a595fceeaa672f0","src/windows.rs":"8e0fa3ab29757d809d4fa03c8101870435ce8c4ceaebe491df3144d62fe0aaaf","tests/client-of-myself.rs":"ca09bf398f69df4bac1730999e954dbbc3faf3c6512678c136e0938e7e9cd0ab","tests/client.rs":"d4745cdd650c86d19bc81f6c9b35df498996deffb86ae6412ad040af96a19183","tests/helper.rs":"c0e6c00eaf849295d8ec23e374690b6645c0f7d993e91abf7ad53ac960f71762","tests/make-as-a-client.rs":"8be1f3fef1e9e65c7904dbaa04364bf0f44e9deab84a2a247a5a94b5cf0df9bc","tests/server.rs":"da15bf12e1df1883f660892b996c9e0d92485aace3f7b50ee70c4a8e6deae8da"},"package":"936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"} \ No newline at end of file
diff --git a/vendor/jobserver/Cargo.toml b/vendor/jobserver/Cargo.toml
index d9a878266..938371008 100644
--- a/vendor/jobserver/Cargo.toml
+++ b/vendor/jobserver/Cargo.toml
@@ -3,21 +3,23 @@
# 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 = "jobserver"
-version = "0.1.24"
+version = "0.1.26"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
-description = "An implementation of the GNU make jobserver for Rust\n"
+description = """
+An implementation of the GNU make jobserver for Rust
+"""
homepage = "https://github.com/alexcrichton/jobserver-rs"
documentation = "https://docs.rs/jobserver"
+readme = "README.md"
license = "MIT/Apache-2.0"
repository = "https://github.com/alexcrichton/jobserver-rs"
@@ -43,19 +45,21 @@ harness = false
[[test]]
name = "helper"
path = "tests/helper.rs"
+
[dev-dependencies.futures]
version = "0.1"
[dev-dependencies.num_cpus]
version = "1.0"
-[dev-dependencies.tempdir]
-version = "0.3"
+[dev-dependencies.tempfile]
+version = "3"
[dev-dependencies.tokio-core]
version = "0.1"
[dev-dependencies.tokio-process]
version = "0.2"
+
[target."cfg(unix)".dependencies.libc]
version = "0.2.50"
diff --git a/vendor/jobserver/src/lib.rs b/vendor/jobserver/src/lib.rs
index 72c02c120..cd0cdd749 100644
--- a/vendor/jobserver/src/lib.rs
+++ b/vendor/jobserver/src/lib.rs
@@ -11,7 +11,10 @@
//! The jobserver implementation can be found in [detail online][docs] but
//! basically boils down to a cross-process semaphore. On Unix this is
//! implemented with the `pipe` syscall and read/write ends of a pipe and on
-//! Windows this is implemented literally with IPC semaphores.
+//! Windows this is implemented literally with IPC semaphores. Starting from
+//! GNU `make` version 4.4, named pipe becomes the default way in communication
+//! on Unix. This crate also supports that feature in the sense of inheriting
+//! and forwarding the correct environment.
//!
//! The jobserver protocol in `make` also dictates when tokens are acquired to
//! run child work, and clients using this crate should take care to implement
@@ -208,7 +211,7 @@ impl Client {
/// with `CLOEXEC` so they're not automatically inherited by spawned
/// children.
///
- /// # Unsafety
+ /// # Safety
///
/// This function is `unsafe` to call on Unix specifically as it
/// transitively requires usage of the `from_raw_fd` function, which is
@@ -273,6 +276,19 @@ impl Client {
})
}
+ /// Returns amount of tokens in the read-side pipe.
+ ///
+ /// # Return value
+ ///
+ /// Number of bytes available to be read from the jobserver pipe
+ ///
+ /// # Errors
+ ///
+ /// Underlying errors from the ioctl will be passed up.
+ pub fn available(&self) -> io::Result<usize> {
+ self.inner.available()
+ }
+
/// Configures a child process to have access to this client's jobserver as
/// well.
///
@@ -290,13 +306,41 @@ impl Client {
///
/// On platforms other than Unix and Windows this panics.
pub fn configure(&self, cmd: &mut Command) {
+ cmd.env("CARGO_MAKEFLAGS", &self.mflags_env());
+ self.inner.configure(cmd);
+ }
+
+ /// Configures a child process to have access to this client's jobserver as
+ /// well.
+ ///
+ /// This function is required to be called to ensure that a jobserver is
+ /// properly inherited to a child process. If this function is *not* called
+ /// then this `Client` will not be accessible in the child process. In other
+ /// words, if not called, then `Client::from_env` will return `None` in the
+ /// child process (or the equivalent of `Child::from_env` that `make` uses).
+ ///
+ /// ## Platform-specific behavior
+ ///
+ /// On Unix and Windows this will clobber the `CARGO_MAKEFLAGS`,
+ /// `MAKEFLAGS` and `MFLAGS` environment variables for the child process,
+ /// and on Unix this will also allow the two file descriptors for
+ /// this client to be inherited to the child.
+ ///
+ /// On platforms other than Unix and Windows this panics.
+ pub fn configure_make(&self, cmd: &mut Command) {
+ let value = self.mflags_env();
+ cmd.env("CARGO_MAKEFLAGS", &value);
+ cmd.env("MAKEFLAGS", &value);
+ cmd.env("MFLAGS", &value);
+ self.inner.configure(cmd);
+ }
+
+ fn mflags_env(&self) -> String {
let arg = self.inner.string_arg();
// Older implementations of make use `--jobserver-fds` and newer
// implementations use `--jobserver-auth`, pass both to try to catch
// both implementations.
- let value = format!("-j --jobserver-fds={0} --jobserver-auth={0}", arg);
- cmd.env("CARGO_MAKEFLAGS", &value);
- self.inner.configure(cmd);
+ format!("-j --jobserver-fds={0} --jobserver-auth={0}", arg)
}
/// Converts this `Client` into a helper thread to deal with a blocking
diff --git a/vendor/jobserver/src/unix.rs b/vendor/jobserver/src/unix.rs
index d69ae88e3..e4b143505 100644
--- a/vendor/jobserver/src/unix.rs
+++ b/vendor/jobserver/src/unix.rs
@@ -1,8 +1,11 @@
use libc::c_int;
-use std::fs::File;
+
+use std::fs::{File, OpenOptions};
use std::io::{self, Read, Write};
use std::mem;
+use std::mem::MaybeUninit;
use std::os::unix::prelude::*;
+use std::path::{Path, PathBuf};
use std::process::Command;
use std::ptr;
use std::sync::{Arc, Once};
@@ -10,9 +13,11 @@ use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;
#[derive(Debug)]
-pub struct Client {
- read: File,
- write: File,
+pub enum Client {
+ /// `--jobserver-auth=R,W`
+ Pipe { read: File, write: File },
+ /// `--jobserver-auth=fifo:PATH`
+ Fifo { file: File, path: PathBuf },
}
#[derive(Debug)]
@@ -21,13 +26,26 @@ pub struct Acquired {
}
impl Client {
- pub fn new(limit: usize) -> io::Result<Client> {
+ pub fn new(mut limit: usize) -> io::Result<Client> {
let client = unsafe { Client::mk()? };
+
// I don't think the character written here matters, but I could be
// wrong!
- for _ in 0..limit {
- (&client.write).write_all(&[b'|'])?;
+ const BUFFER: [u8; 128] = [b'|'; 128];
+
+ let mut write = client.write();
+
+ set_nonblocking(write.as_raw_fd(), true)?;
+
+ while limit > 0 {
+ let n = limit.min(BUFFER.len());
+
+ write.write_all(&BUFFER[..n])?;
+ limit -= n;
}
+
+ set_nonblocking(write.as_raw_fd(), false)?;
+
Ok(client)
}
@@ -64,6 +82,31 @@ impl Client {
}
pub unsafe fn open(s: &str) -> Option<Client> {
+ Client::from_fifo(s).or_else(|| Client::from_pipe(s))
+ }
+
+ /// `--jobserver-auth=fifo:PATH`
+ fn from_fifo(s: &str) -> Option<Client> {
+ let mut parts = s.splitn(2, ':');
+ if parts.next().unwrap() != "fifo" {
+ return None;
+ }
+ let path = match parts.next() {
+ Some(p) => Path::new(p),
+ None => return None,
+ };
+ let file = match OpenOptions::new().read(true).write(true).open(path) {
+ Ok(f) => f,
+ Err(_) => return None,
+ };
+ Some(Client::Fifo {
+ file,
+ path: path.into(),
+ })
+ }
+
+ /// `--jobserver-auth=R,W`
+ unsafe fn from_pipe(s: &str) -> Option<Client> {
let mut parts = s.splitn(2, ',');
let read = parts.next().unwrap();
let write = match parts.next() {
@@ -97,12 +140,28 @@ impl Client {
}
unsafe fn from_fds(read: c_int, write: c_int) -> Client {
- Client {
+ Client::Pipe {
read: File::from_raw_fd(read),
write: File::from_raw_fd(write),
}
}
+ /// Gets the read end of our jobserver client.
+ fn read(&self) -> &File {
+ match self {
+ Client::Pipe { read, .. } => read,
+ Client::Fifo { file, .. } => file,
+ }
+ }
+
+ /// Gets the write end of our jobserver client.
+ fn write(&self) -> &File {
+ match self {
+ Client::Pipe { write, .. } => write,
+ Client::Fifo { file, .. } => file,
+ }
+ }
+
pub fn acquire(&self) -> io::Result<Acquired> {
// Ignore interrupts and keep trying if that happens
loop {
@@ -137,11 +196,12 @@ impl Client {
// to shut us down, so we otherwise punt all errors upwards.
unsafe {
let mut fd: libc::pollfd = mem::zeroed();
- fd.fd = self.read.as_raw_fd();
+ let mut read = self.read();
+ fd.fd = read.as_raw_fd();
fd.events = libc::POLLIN;
loop {
let mut buf = [0];
- match (&self.read).read(&mut buf) {
+ match read.read(&mut buf) {
Ok(1) => return Ok(Some(Acquired { byte: buf[0] })),
Ok(_) => {
return Err(io::Error::new(
@@ -179,7 +239,7 @@ impl Client {
// always quickly release a token). If that turns out to not be the
// case we'll get an error anyway!
let byte = data.map(|d| d.byte).unwrap_or(b'+');
- match (&self.write).write(&[byte])? {
+ match self.write().write(&[byte])? {
1 => Ok(()),
_ => Err(io::Error::new(
io::ErrorKind::Other,
@@ -189,16 +249,31 @@ impl Client {
}
pub fn string_arg(&self) -> String {
- format!("{},{}", self.read.as_raw_fd(), self.write.as_raw_fd())
+ match self {
+ Client::Pipe { read, write } => format!("{},{}", read.as_raw_fd(), write.as_raw_fd()),
+ Client::Fifo { path, .. } => format!("fifo:{}", path.to_str().unwrap()),
+ }
+ }
+
+ pub fn available(&self) -> io::Result<usize> {
+ let mut len = MaybeUninit::<c_int>::uninit();
+ cvt(unsafe { libc::ioctl(self.read().as_raw_fd(), libc::FIONREAD, len.as_mut_ptr()) })?;
+ Ok(unsafe { len.assume_init() } as usize)
}
pub fn configure(&self, cmd: &mut Command) {
+ match self {
+ // We `File::open`ed it when inheriting from environment,
+ // so no need to set cloexec for fifo.
+ Client::Fifo { .. } => return,
+ Client::Pipe { .. } => {}
+ };
// Here we basically just want to say that in the child process
// we'll configure the read/write file descriptors to *not* be
// cloexec, so they're inherited across the exec and specified as
// integers through `string_arg` above.
- let read = self.read.as_raw_fd();
- let write = self.write.as_raw_fd();
+ let read = self.read().as_raw_fd();
+ let write = self.write().as_raw_fd();
unsafe {
cmd.pre_exec(move || {
set_cloexec(read, false)?;
@@ -224,7 +299,14 @@ pub(crate) fn spawn_helper(
let mut err = None;
USR1_INIT.call_once(|| unsafe {
let mut new: libc::sigaction = mem::zeroed();
- new.sa_sigaction = sigusr1_handler as usize;
+ #[cfg(target_os = "aix")]
+ {
+ new.sa_union.__su_sigaction = sigusr1_handler;
+ }
+ #[cfg(not(target_os = "aix"))]
+ {
+ new.sa_sigaction = sigusr1_handler as usize;
+ }
new.sa_flags = libc::SA_SIGINFO as _;
if libc::sigaction(libc::SIGUSR1, &new, ptr::null_mut()) != 0 {
err = Some(io::Error::last_os_error());
@@ -322,6 +404,16 @@ fn set_cloexec(fd: c_int, set: bool) -> io::Result<()> {
}
}
+fn set_nonblocking(fd: c_int, set: bool) -> io::Result<()> {
+ let status_flag = if set { libc::O_NONBLOCK } else { 0 };
+
+ unsafe {
+ cvt(libc::fcntl(fd, libc::F_SETFL, status_flag))?;
+ }
+
+ Ok(())
+}
+
fn cvt(t: c_int) -> io::Result<c_int> {
if t == -1 {
Err(io::Error::last_os_error())
diff --git a/vendor/jobserver/src/wasm.rs b/vendor/jobserver/src/wasm.rs
index b88a9d952..3793bd67c 100644
--- a/vendor/jobserver/src/wasm.rs
+++ b/vendor/jobserver/src/wasm.rs
@@ -59,6 +59,11 @@ impl Client {
);
}
+ pub fn available(&self) -> io::Result<usize> {
+ let lock = self.inner.count.lock().unwrap_or_else(|e| e.into_inner());
+ Ok(*lock)
+ }
+
pub fn configure(&self, _cmd: &mut Command) {
unreachable!();
}
diff --git a/vendor/jobserver/src/windows.rs b/vendor/jobserver/src/windows.rs
index d795c1cee..6791efea4 100644
--- a/vendor/jobserver/src/windows.rs
+++ b/vendor/jobserver/src/windows.rs
@@ -170,6 +170,26 @@ impl Client {
self.name.clone()
}
+ pub fn available(&self) -> io::Result<usize> {
+ // Can't read value of a semaphore on Windows, so
+ // try to acquire without sleeping, since we can find out the
+ // old value on release. If acquisiton fails, then available is 0.
+ unsafe {
+ let r = WaitForSingleObject(self.sem.0, 0);
+ if r != WAIT_OBJECT_0 {
+ Ok(0)
+ } else {
+ let mut prev: LONG = 0;
+ let r = ReleaseSemaphore(self.sem.0, 1, &mut prev);
+ if r != 0 {
+ Ok(prev as usize + 1)
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+ }
+
pub fn configure(&self, _cmd: &mut Command) {
// nothing to do here, we gave the name of our semaphore to the
// child above
diff --git a/vendor/jobserver/tests/client.rs b/vendor/jobserver/tests/client.rs
index 7f319c09c..2516b8ccf 100644
--- a/vendor/jobserver/tests/client.rs
+++ b/vendor/jobserver/tests/client.rs
@@ -10,7 +10,6 @@ use std::thread;
use futures::future::{self, Future};
use futures::stream::{self, Stream};
use jobserver::Client;
-use tempdir::TempDir;
use tokio_core::reactor::Core;
use tokio_process::CommandExt;
@@ -128,7 +127,7 @@ fn main() {
None => true,
})
.map(|test| {
- let td = t!(TempDir::new("foo"));
+ let td = t!(tempfile::tempdir());
let makefile = format!(
"\
all: export TEST_TO_RUN={}
diff --git a/vendor/jobserver/tests/make-as-a-client.rs b/vendor/jobserver/tests/make-as-a-client.rs
index e530211b0..4faac5b88 100644
--- a/vendor/jobserver/tests/make-as-a-client.rs
+++ b/vendor/jobserver/tests/make-as-a-client.rs
@@ -5,7 +5,6 @@ use std::net::{TcpListener, TcpStream};
use std::process::Command;
use jobserver::Client;
-use tempdir::TempDir;
macro_rules! t {
($e:expr) => {
@@ -37,7 +36,7 @@ fn main() {
}
let c = t!(Client::new(1));
- let td = TempDir::new("foo").unwrap();
+ let td = tempfile::tempdir().unwrap();
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
diff --git a/vendor/jobserver/tests/server.rs b/vendor/jobserver/tests/server.rs
index fcdd12ca2..70ea218fc 100644
--- a/vendor/jobserver/tests/server.rs
+++ b/vendor/jobserver/tests/server.rs
@@ -8,7 +8,6 @@ use std::sync::Arc;
use std::thread;
use jobserver::Client;
-use tempdir::TempDir;
macro_rules! t {
($e:expr) => {
@@ -35,6 +34,30 @@ fn server_multiple() {
}
#[test]
+fn server_available() {
+ let c = t!(Client::new(10));
+ assert_eq!(c.available().unwrap(), 10);
+ let a = c.acquire().unwrap();
+ assert_eq!(c.available().unwrap(), 9);
+ drop(a);
+ assert_eq!(c.available().unwrap(), 10);
+}
+
+#[test]
+fn server_none_available() {
+ let c = t!(Client::new(2));
+ assert_eq!(c.available().unwrap(), 2);
+ let a = c.acquire().unwrap();
+ assert_eq!(c.available().unwrap(), 1);
+ let b = c.acquire().unwrap();
+ assert_eq!(c.available().unwrap(), 0);
+ drop(a);
+ assert_eq!(c.available().unwrap(), 1);
+ drop(b);
+ assert_eq!(c.available().unwrap(), 2);
+}
+
+#[test]
fn server_blocks() {
let c = t!(Client::new(1));
let a = c.acquire().unwrap();
@@ -56,7 +79,7 @@ fn server_blocks() {
#[test]
fn make_as_a_single_thread_client() {
let c = t!(Client::new(1));
- let td = TempDir::new("foo").unwrap();
+ let td = tempfile::tempdir().unwrap();
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
let mut cmd = Command::new(prog);
@@ -110,7 +133,7 @@ foo
#[test]
fn make_as_a_multi_thread_client() {
let c = t!(Client::new(1));
- let td = TempDir::new("foo").unwrap();
+ let td = tempfile::tempdir().unwrap();
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
let mut cmd = Command::new(prog);