-use jobserver_crate::{Client, HelperThread, Acquired};
+use jobserver_crate::Client;
use lazy_static::lazy_static;
-use std::sync::{Condvar, Arc, Mutex};
-use std::mem;
-
-#[derive(Default)]
-struct LockedProxyData {
- /// The number of free thread tokens, this may include the implicit token given to the process
- free: usize,
-
- /// The number of threads waiting for a token
- waiters: usize,
-
- /// The number of tokens we requested from the server
- requested: usize,
-
- /// Stored tokens which will be dropped when we no longer need them
- tokens: Vec<Acquired>,
-}
-
-impl LockedProxyData {
- fn request_token(&mut self, thread: &Mutex<HelperThread>) {
- self.requested += 1;
- thread.lock().unwrap().request_token();
- }
-
- fn release_token(&mut self, cond_var: &Condvar) {
- if self.waiters > 0 {
- self.free += 1;
- cond_var.notify_one();
- } else {
- if self.tokens.is_empty() {
- // We are returning the implicit token
- self.free += 1;
- } else {
- // Return a real token to the server
- self.tokens.pop().unwrap();
- }
- }
- }
-
- fn take_token(&mut self, thread: &Mutex<HelperThread>) -> bool {
- if self.free > 0 {
- self.free -= 1;
- self.waiters -= 1;
-
- // We stole some token reqested by someone else
- // Request another one
- if self.requested + self.free < self.waiters {
- self.request_token(thread);
- }
-
- true
- } else {
- false
- }
- }
-
- fn new_requested_token(&mut self, token: Acquired, cond_var: &Condvar) {
- self.requested -= 1;
-
- // Does anything need this token?
- if self.waiters > 0 {
- self.free += 1;
- self.tokens.push(token);
- cond_var.notify_one();
- } else {
- // Otherwise we'll just drop it
- mem::drop(token);
- }
- }
-}
-
-#[derive(Default)]
-struct ProxyData {
- lock: Mutex<LockedProxyData>,
- cond_var: Condvar,
-}
-
-/// A helper type which makes managing jobserver tokens easier.
-/// It also allows you to treat the implicit token given to the process
-/// in the same manner as requested tokens.
-struct Proxy {
- thread: Mutex<HelperThread>,
- data: Arc<ProxyData>,
-}
lazy_static! {
// We can only call `from_env` once per process
// per-process.
static ref GLOBAL_CLIENT: Client = unsafe {
Client::from_env().unwrap_or_else(|| {
- Client::new(32).expect("failed to create jobserver")
+ let client = Client::new(32).expect("failed to create jobserver");
+ // Acquire a token for the main thread which we can release later
+ client.acquire_raw().ok();
+ client
})
};
-
- static ref GLOBAL_PROXY: Proxy = {
- let data = Arc::new(ProxyData::default());
-
- Proxy {
- data: data.clone(),
- thread: Mutex::new(client().into_helper_thread(move |token| {
- data.lock.lock().unwrap().new_requested_token(token.unwrap(), &data.cond_var);
- }).unwrap()),
- }
- };
}
pub fn client() -> Client {
}
pub fn acquire_thread() {
- GLOBAL_PROXY.acquire_token();
+ GLOBAL_CLIENT.acquire_raw().ok();
}
pub fn release_thread() {
- GLOBAL_PROXY.release_token();
-}
-
-impl Proxy {
- fn release_token(&self) {
- self.data.lock.lock().unwrap().release_token(&self.data.cond_var);
- }
-
- fn acquire_token(&self) {
- let mut data = self.data.lock.lock().unwrap();
- data.waiters += 1;
- if data.take_token(&self.thread) {
- return;
- }
- // Request a token for us
- data.request_token(&self.thread);
- loop {
- data = self.data.cond_var.wait(data).unwrap();
- if data.take_token(&self.thread) {
- return;
- }
- }
- }
+ GLOBAL_CLIENT.release_raw().ok();
}