Skip to content

Commit

Permalink
Add available traits to find out how many client tokens are unused
Browse files Browse the repository at this point in the history
Returns amount of tokens in the read-side pipe (number of jobs that could be started).

Signed-off-by: Olof Johansson <olof@lixom.net>
  • Loading branch information
olofj committed Sep 22, 2022
1 parent 2c7fbf0 commit cfae7ff
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,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.
///
Expand Down
7 changes: 7 additions & 0 deletions src/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use libc::c_int;
use std::fs::File;
use std::io::{self, Read, Write};
use std::mem;
use std::mem::MaybeUninit;
use std::os::unix::prelude::*;
use std::process::Command;
use std::ptr;
Expand Down Expand Up @@ -204,6 +205,12 @@ impl Client {
format!("{},{}", self.read.as_raw_fd(), self.write.as_raw_fd())
}

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) {
// Here we basically just want to say that in the child process
// we'll configure the read/write file descriptors to *not* be
Expand Down
5 changes: 5 additions & 0 deletions src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!();
}
Expand Down
20 changes: 20 additions & 0 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,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));
Expand Down

0 comments on commit cfae7ff

Please sign in to comment.