Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for non-unix and non-windows platforms #13

Merged
merged 7 commits into from
May 17, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ impl Client {
/// On Unix and Windows this will clobber the `CARGO_MAKEFLAGS` 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.
///
/// This method doesn't exist on platforms other than Unix and Windows, as
/// those don't have a real jobserver implementation.
#[cfg(any(unix, windows))]
bjorn3 marked this conversation as resolved.
Show resolved Hide resolved
pub fn configure(&self, cmd: &mut Command) {
let arg = self.inner.string_arg();
// Older implementations of make use `--jobserver-fds` and newer
Expand Down Expand Up @@ -961,3 +965,114 @@ mod imp {
}
}
}

#[cfg(not(any(unix, windows)))]
mod imp {
use std::io;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, SyncSender, Receiver, RecvTimeoutError};
use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;

#[derive(Debug)]
pub struct Client {
tx: SyncSender<()>,
rx: Mutex<Receiver<()>>,
}

#[derive(Debug)]
pub struct Acquired(());

impl Client {
pub fn new(limit: usize) -> io::Result<Client> {
let (tx, rx) = mpsc::sync_channel(limit);
for _ in 0..limit {
tx.send(()).unwrap();
}
Ok(Client {
tx,
rx: Mutex::new(rx),
})
}

pub unsafe fn open(_s: &str) -> Option<Client> {
None
}

pub fn acquire(&self) -> io::Result<Acquired> {
self.rx.lock().unwrap().recv().unwrap();
Ok(Acquired(()))
}

pub fn release(&self, _data: Option<&Acquired>) -> io::Result<()> {
self.tx.send(()).unwrap();
Ok(())
}
}

#[derive(Debug)]
pub struct Helper {
thread: JoinHandle<()>,
quitting: Arc<AtomicBool>,
rx_done: Receiver<()>,
}

pub fn spawn_helper(client: ::Client,
rx: Receiver<()>,
mut f: Box<FnMut(io::Result<::Acquired>) + Send>)
-> io::Result<Helper>
{
let quitting = Arc::new(AtomicBool::new(false));
let quitting2 = quitting.clone();
let (tx_done, rx_done) = mpsc::channel();
let thread = Builder::new().spawn(move || {
'outer:
for () in rx {
loop {
let res = client.acquire();
if let Err(ref e) = res {
if e.kind() == io::ErrorKind::Interrupted {
if quitting2.load(Ordering::SeqCst) {
break 'outer
} else {
continue
}
}
}
f(res);
break
}
bjorn3 marked this conversation as resolved.
Show resolved Hide resolved
}
tx_done.send(()).unwrap();
})?;

Ok(Helper {
thread: thread,
quitting: quitting,
rx_done: rx_done,
})
}

impl Helper {
pub fn join(self) {
self.quitting.store(true, Ordering::SeqCst);
bjorn3 marked this conversation as resolved.
Show resolved Hide resolved
let dur = Duration::from_millis(10);
let mut done = false;
for _ in 0..100 {
bjorn3 marked this conversation as resolved.
Show resolved Hide resolved
match self.rx_done.recv_timeout(dur) {
Ok(()) |
Err(RecvTimeoutError::Disconnected) => {
done = true;
break
}
Err(RecvTimeoutError::Timeout) => {}
}
thread::yield_now();
}
if done {
drop(self.thread.join());
}
}
}
}