From 4f9fe856a25ab29345b90e7725509e9ee38a37be Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:41 +0200 Subject: Adding upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/jobserver/src/unix.rs | 122 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 15 deletions(-) (limited to 'vendor/jobserver/src/unix.rs') 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()) -- cgit v1.2.3