From 2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:50 +0200 Subject: Merging upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/jobserver/.cargo-checksum.json | 2 +- vendor/jobserver/Cargo.toml | 22 +++--- vendor/jobserver/src/lib.rs | 54 +++++++++++-- vendor/jobserver/src/unix.rs | 122 +++++++++++++++++++++++++---- vendor/jobserver/src/wasm.rs | 5 ++ vendor/jobserver/src/windows.rs | 20 +++++ vendor/jobserver/tests/client.rs | 3 +- vendor/jobserver/tests/make-as-a-client.rs | 3 +- vendor/jobserver/tests/server.rs | 29 ++++++- 9 files changed, 223 insertions(+), 37 deletions(-) (limited to 'vendor/jobserver') 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 "] -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 { + 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 { + pub fn new(mut limit: usize) -> io::Result { 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::from_fifo(s).or_else(|| Client::from_pipe(s)) + } + + /// `--jobserver-auth=fifo:PATH` + fn from_fifo(s: &str) -> Option { + 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 { 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 { // 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 { + let mut len = MaybeUninit::::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 { 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 { + 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 { + // 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) => { @@ -34,6 +33,30 @@ fn server_multiple() { drop((a, b)); } +#[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)); @@ -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); -- cgit v1.2.3