use std::io; use std::process::Command; use std::sync::{Arc, Condvar, Mutex}; use std::thread::{Builder, JoinHandle}; #[derive(Debug)] pub struct Client { inner: Arc, } #[derive(Debug)] struct Inner { count: Mutex, cvar: Condvar, } #[derive(Debug)] pub struct Acquired(()); impl Client { pub fn new(limit: usize) -> io::Result { Ok(Client { inner: Arc::new(Inner { count: Mutex::new(limit), cvar: Condvar::new(), }), }) } pub unsafe fn open(_s: &str) -> Option { None } pub fn acquire(&self) -> io::Result { let mut lock = self.inner.count.lock().unwrap_or_else(|e| e.into_inner()); while *lock == 0 { lock = self .inner .cvar .wait(lock) .unwrap_or_else(|e| e.into_inner()); } *lock -= 1; Ok(Acquired(())) } pub fn release(&self, _data: Option<&Acquired>) -> io::Result<()> { let mut lock = self.inner.count.lock().unwrap_or_else(|e| e.into_inner()); *lock += 1; drop(lock); self.inner.cvar.notify_one(); Ok(()) } pub fn string_arg(&self) -> String { panic!( "On this platform there is no cross process jobserver support, so Client::configure is not supported." ); } pub fn configure(&self, _cmd: &mut Command) { unreachable!(); } } #[derive(Debug)] pub struct Helper { thread: JoinHandle<()>, } pub(crate) fn spawn_helper( client: crate::Client, state: Arc, mut f: Box) + Send>, ) -> io::Result { let thread = Builder::new().spawn(move || { state.for_each_request(|_| f(client.acquire())); })?; Ok(Helper { thread: thread }) } impl Helper { pub fn join(self) { // TODO: this is not correct if the thread is blocked in // `client.acquire()`. drop(self.thread.join()); } }