Skip to content

Commit

Permalink
Merge pull request #45 from olofj/add-available
Browse files Browse the repository at this point in the history
Add `available` traits to find out how many client tokens are unused
  • Loading branch information
alexcrichton authored Sep 22, 2022
2 parents 2c7fbf0 + cfae7ff commit d7a5828
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 d7a5828

Please sign in to comment.