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

Clean up jobserver integration #59804

Merged
merged 1 commit into from
Apr 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion src/librustc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ crate-type = ["dylib"]
[dependencies]
ena = "0.13"
log = "0.4"
jobserver_crate = { version = "0.1", package = "jobserver" }
jobserver_crate = { version = "0.1.13", package = "jobserver" }
lazy_static = "1"
rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
serialize = { path = "../libserialize" }
Expand Down
128 changes: 7 additions & 121 deletions src/librustc_data_structures/jobserver.rs
Original file line number Diff line number Diff line change
@@ -1,89 +1,5 @@
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
Expand All @@ -105,52 +21,22 @@ lazy_static! {
// 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 {
GLOBAL_CLIENT.clone()
}

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();
}