From 59afaf04aaf43333b1768817b7c7df778765a624 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 17:14:46 -0500 Subject: [PATCH 1/9] Move jobserver integration into separate crate Future commits on this branch will make our implementation pretty specific to rustc (i.e., talking to Cargo and such) so coupling ourselves into rustc_data_structures which is intended to be more "agnostic" isn't a great fit. This also removes uses of the jobserver inside rustc that refer directly to the `jobsever` crate (and similar cleanups will follow in the next few commits). --- Cargo.lock | 15 ++++++++++++--- src/librustc/Cargo.toml | 2 +- src/librustc/ty/query/job.rs | 3 ++- src/librustc_codegen_ssa/Cargo.toml | 2 +- src/librustc_codegen_ssa/back/write.rs | 2 +- src/librustc_data_structures/Cargo.toml | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_interface/Cargo.toml | 1 + src/librustc_interface/util.rs | 2 +- src/librustc_jobserver/Cargo.toml | 14 ++++++++++++++ .../jobserver.rs => librustc_jobserver/lib.rs} | 2 +- src/librustc_session/Cargo.toml | 1 + src/librustc_session/session.rs | 2 +- 13 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 src/librustc_jobserver/Cargo.toml rename src/{librustc_data_structures/jobserver.rs => librustc_jobserver/lib.rs} (96%) diff --git a/Cargo.lock b/Cargo.lock index 1af0442dde7fc..da3a7a84f5fe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3151,7 +3151,6 @@ dependencies = [ "chalk-engine", "fmt_macros", "graphviz", - "jobserver", "log", "measureme", "num_cpus", @@ -3166,6 +3165,7 @@ dependencies = [ "rustc_feature", "rustc_fs_util", "rustc_index", + "rustc_jobserver", "rustc_macros", "rustc_session", "rustc_target", @@ -3464,7 +3464,6 @@ version = "0.0.0" dependencies = [ "bitflags", "cc", - "jobserver", "libc", "log", "memmap", @@ -3478,6 +3477,7 @@ dependencies = [ "rustc_fs_util", "rustc_incremental", "rustc_index", + "rustc_jobserver", "rustc_session", "rustc_target", "serialize", @@ -3511,7 +3511,6 @@ dependencies = [ "ena", "graphviz", "indexmap", - "jobserver", "lazy_static 1.3.0", "log", "measureme", @@ -3623,6 +3622,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_incremental", + "rustc_jobserver", "rustc_lint", "rustc_metadata", "rustc_mir", @@ -3643,6 +3643,14 @@ dependencies = [ "tempfile", ] +[[package]] +name = "rustc_jobserver" +version = "0.0.0" +dependencies = [ + "jobserver", + "lazy_static 1.3.0", +] + [[package]] name = "rustc_lexer" version = "0.1.0" @@ -3859,6 +3867,7 @@ dependencies = [ "rustc_feature", "rustc_fs_util", "rustc_index", + "rustc_jobserver", "rustc_target", "serialize", "syntax_pos", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index a4536bb6c41f0..59ca9df503e52 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -14,7 +14,7 @@ arena = { path = "../libarena" } bitflags = "1.2.1" fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -jobserver = "0.1" +rustc_jobserver = { path = "../librustc_jobserver" } num_cpus = "1.0" scoped-tls = "1.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 2f30b797fb151..be50afca03ac4 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -12,7 +12,8 @@ use std::ptr; #[cfg(parallel_compiler)] use { parking_lot::{Mutex, Condvar}, - rustc_data_structures::{jobserver, OnDrop}, + rustc_data_structures::{OnDrop}, + rustc_jobserver as jobserver, rustc_data_structures::fx::FxHashSet, rustc_data_structures::stable_hasher::{StableHasher, HashStable}, rustc_data_structures::sync::Lock, diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index d489852a1a43d..065abd4279331 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -16,7 +16,6 @@ num_cpus = "1.0" memmap = "0.7" log = "0.4.5" libc = "0.2.44" -jobserver = "0.1.11" tempfile = "3.1" rustc_serialize = { path = "../libserialize", package = "serialize" } @@ -33,3 +32,4 @@ rustc_index = { path = "../librustc_index" } rustc_target = { path = "../librustc_target" } rustc_error_codes = { path = "../librustc_error_codes" } rustc_session = { path = "../librustc_session" } +rustc_jobserver = { path = "../librustc_jobserver" } diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 283295cadfcc5..9a39bb8e2397a 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -30,7 +30,7 @@ use rustc_target::spec::MergeFunctions; use syntax::attr; use syntax_pos::hygiene::ExpnId; use syntax_pos::symbol::{Symbol, sym}; -use jobserver::{Client, Acquired}; +use rustc_jobserver::{Client, Acquired}; use std::any::Any; use std::fs; diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 7fa40b8a86905..333bd11da6259 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -13,7 +13,6 @@ doctest = false ena = "0.13.1" indexmap = "1" log = "0.4" -jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" rustc_serialize = { path = "../libserialize", package = "serialize" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 02611a36aaebc..93795913bbc1c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -75,7 +75,6 @@ pub mod flock; pub mod fx; pub mod stable_map; pub mod graph; -pub mod jobserver; pub mod obligation_forest; pub mod owning_ref; pub mod ptr_key; diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 58fd92822e9a2..238dc6449f2e6 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -23,6 +23,7 @@ rustc = { path = "../librustc" } rustc_incremental = { path = "../librustc_incremental" } rustc_traits = { path = "../librustc_traits" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_jobserver = { path = "../librustc_jobserver" } rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index c78b3ee07676e..9fa28ac4eaa04 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -6,7 +6,7 @@ use rustc::ty; use rustc::lint; use rustc_codegen_utils::codegen_backend::CodegenBackend; #[cfg(parallel_compiler)] -use rustc_data_structures::jobserver; +use rustc_jobserver as jobserver; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::fingerprint::Fingerprint; diff --git a/src/librustc_jobserver/Cargo.toml b/src/librustc_jobserver/Cargo.toml new file mode 100644 index 0000000000000..223dac54c874d --- /dev/null +++ b/src/librustc_jobserver/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_jobserver" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_jobserver" +path = "lib.rs" +doctest = false + +[dependencies] +jobserver_crate = { version = "0.1.13", package = "jobserver" } +lazy_static = "1" diff --git a/src/librustc_data_structures/jobserver.rs b/src/librustc_jobserver/lib.rs similarity index 96% rename from src/librustc_data_structures/jobserver.rs rename to src/librustc_jobserver/lib.rs index a811c88839d70..1c0b3d9769287 100644 --- a/src/librustc_data_structures/jobserver.rs +++ b/src/librustc_jobserver/lib.rs @@ -1,4 +1,4 @@ -pub use jobserver_crate::Client; +pub use jobserver_crate::{Acquired, Client}; use lazy_static::lazy_static; lazy_static! { diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml index dbbb4b92dea35..a0ec86f403b9f 100644 --- a/src/librustc_session/Cargo.toml +++ b/src/librustc_session/Cargo.toml @@ -19,3 +19,4 @@ syntax_pos = { path = "../libsyntax_pos" } rustc_index = { path = "../librustc_index" } rustc_fs_util = { path = "../librustc_fs_util" } num_cpus = "1.0" +rustc_jobserver = { path = "../librustc_jobserver" } diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 4e72249aed129..ad46023a5d77e 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -31,7 +31,7 @@ use syntax_pos::{MultiSpan, Span}; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; use rustc_data_structures::flock; -use rustc_data_structures::jobserver::{self, Client}; +use rustc_jobserver::{self as jobserver, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use std; From aa378237bafb5f8338ca2764a4d34645fb86b431 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 17:26:01 -0500 Subject: [PATCH 2/9] Remove jobserver Client from Session We want to restrict access to the raw Client and this is the first step to doing so; the client is still initialized from the environment at the same time. --- src/librustc_codegen_ssa/back/write.rs | 2 +- src/librustc_jobserver/lib.rs | 4 ++++ src/librustc_session/session.rs | 8 ++------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 9a39bb8e2397a..a529856382573 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -433,7 +433,7 @@ pub fn start_async_codegen( codegen_worker_send, coordinator_receive, total_cgus, - sess.jobserver.clone(), + rustc_jobserver::client(), Arc::new(modules_config), Arc::new(metadata_config), Arc::new(allocator_config), diff --git a/src/librustc_jobserver/lib.rs b/src/librustc_jobserver/lib.rs index 1c0b3d9769287..28a1483ae3867 100644 --- a/src/librustc_jobserver/lib.rs +++ b/src/librustc_jobserver/lib.rs @@ -29,6 +29,10 @@ lazy_static! { }; } +pub fn initialize() { + lazy_static::initialize(&GLOBAL_CLIENT) +} + pub fn client() -> Client { GLOBAL_CLIENT.clone() } diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index ad46023a5d77e..937949c91a501 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -31,7 +31,6 @@ use syntax_pos::{MultiSpan, Span}; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; use rustc_data_structures::flock; -use rustc_jobserver::{self as jobserver, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use std; @@ -121,10 +120,6 @@ pub struct Session { /// Always set to zero and incremented so that we can print fuel expended by a crate. pub print_fuel: AtomicUsize, - /// Loaded up early on in the initialization of this `Session` to avoid - /// false positives about a job server in our environment. - pub jobserver: Client, - /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap, @@ -1131,6 +1126,8 @@ fn build_session_( CguReuseTracker::new_disabled() }; + rustc_jobserver::initialize(); + let sess = Session { target: target_cfg, host, @@ -1163,7 +1160,6 @@ fn build_session_( optimization_fuel, print_fuel_crate, print_fuel, - jobserver: jobserver::client(), driver_lint_caps, trait_methods_not_found: Lock::new(Default::default()), confused_type_with_std_module: Lock::new(Default::default()), From 8d9ba0ed84d44c13de580a8075adeff302a5b014 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 17:55:47 -0500 Subject: [PATCH 3/9] Send raw tokens through the LLVM coordination channel Sending an io::Result of the acquired token is a bit odd as the receiver can't productively do anything on error (other than panic) and largely if we've encountered an error when reading from the pipe it's not something that we expect to happen (i.e., likely indicates something has gone wrong outside our control or is a rustc programmer error) so a panic is appropriate. --- src/librustc_codegen_ssa/back/write.rs | 32 +++++++++----------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index a529856382573..503cd1bca1de0 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -34,7 +34,6 @@ use rustc_jobserver::{Client, Acquired}; use std::any::Any; use std::fs; -use std::io; use std::mem; use std::path::{Path, PathBuf}; use std::str; @@ -890,7 +889,7 @@ fn execute_lto_work_item( } pub enum Message { - Token(io::Result), + Token(Acquired), NeedsFatLTO { result: FatLTOInput, worker_id: usize, @@ -982,6 +981,7 @@ fn start_executing_work( // get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); let helper = jobserver.into_helper_thread(move |token| { + let token = token.expect("acquired token successfully"); drop(coordinator_send2.send(Box::new(Message::Token::(token)))); }).expect("failed to spawn helper thread"); @@ -1374,25 +1374,15 @@ fn start_executing_work( // this to spawn a new unit of work, or it may get dropped // immediately if we have no more work to spawn. Message::Token(token) => { - match token { - Ok(token) => { - tokens.push(token); - - if main_thread_worker_state == MainThreadWorkerState::LLVMing { - // If the main thread token is used for LLVM work - // at the moment, we turn that thread into a regular - // LLVM worker thread, so the main thread is free - // to react to codegen demand. - main_thread_worker_state = MainThreadWorkerState::Idle; - running += 1; - } - } - Err(e) => { - let msg = &format!("failed to acquire jobserver token: {}", e); - shared_emitter.fatal(msg); - // Exit the coordinator thread - panic!("{}", msg) - } + tokens.push(token); + + if main_thread_worker_state == MainThreadWorkerState::LLVMing { + // If the main thread token is used for LLVM work + // at the moment, we turn that thread into a regular + // LLVM worker thread, so the main thread is free + // to react to codegen demand. + main_thread_worker_state = MainThreadWorkerState::Idle; + running += 1; } } From 24cf5a3a037acca04c7b836e400305f542fe63b6 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 18:01:12 -0500 Subject: [PATCH 4/9] Stop depending on rustc_jobserver::Client --- src/librustc_codegen_ssa/back/write.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 503cd1bca1de0..f82f926120d0d 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -30,7 +30,7 @@ use rustc_target::spec::MergeFunctions; use syntax::attr; use syntax_pos::hygiene::ExpnId; use syntax_pos::symbol::{Symbol, sym}; -use rustc_jobserver::{Client, Acquired}; +use rustc_jobserver::Acquired; use std::any::Any; use std::fs; @@ -432,7 +432,6 @@ pub fn start_async_codegen( codegen_worker_send, coordinator_receive, total_cgus, - rustc_jobserver::client(), Arc::new(modules_config), Arc::new(metadata_config), Arc::new(allocator_config), @@ -937,7 +936,6 @@ fn start_executing_work( codegen_worker_send: Sender>, coordinator_receive: Receiver>, total_cgus: usize, - jobserver: Client, modules_config: Arc, metadata_config: Arc, allocator_config: Arc, @@ -980,7 +978,7 @@ fn start_executing_work( // get tokens on `coordinator_receive` which will // get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); - let helper = jobserver.into_helper_thread(move |token| { + let helper = rustc_jobserver::client().into_helper_thread(move |token| { let token = token.expect("acquired token successfully"); drop(coordinator_send2.send(Box::new(Message::Token::(token)))); }).expect("failed to spawn helper thread"); From 2c9854cf28117379f5697415c82efbd362900b17 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 18:08:05 -0500 Subject: [PATCH 5/9] Hide the jobserver Client from the public view Future commits will be changing the jobserver integration to have custom logic to enable it to appropriately talk to Cargo, so we can't have other code that directly talks to the jobserver. --- src/librustc_codegen_ssa/back/write.rs | 5 ++--- src/librustc_jobserver/lib.rs | 11 ++++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index f82f926120d0d..6a3f2d0a1ee01 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -978,10 +978,9 @@ fn start_executing_work( // get tokens on `coordinator_receive` which will // get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); - let helper = rustc_jobserver::client().into_helper_thread(move |token| { - let token = token.expect("acquired token successfully"); + let helper = rustc_jobserver::helper_thread(move |token| { drop(coordinator_send2.send(Box::new(Message::Token::(token)))); - }).expect("failed to spawn helper thread"); + }); let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(crate_info, &mut |cnum, path| { diff --git a/src/librustc_jobserver/lib.rs b/src/librustc_jobserver/lib.rs index 28a1483ae3867..9050346691917 100644 --- a/src/librustc_jobserver/lib.rs +++ b/src/librustc_jobserver/lib.rs @@ -1,4 +1,5 @@ -pub use jobserver_crate::{Acquired, Client}; +pub use jobserver_crate::Acquired; +use jobserver_crate::{HelperThread, Client}; use lazy_static::lazy_static; lazy_static! { @@ -33,8 +34,12 @@ pub fn initialize() { lazy_static::initialize(&GLOBAL_CLIENT) } -pub fn client() -> Client { - GLOBAL_CLIENT.clone() +pub fn helper_thread(mut cb: F) -> HelperThread + where F: FnMut(Acquired) + Send + 'static, +{ + GLOBAL_CLIENT.clone().into_helper_thread(move |token| { + cb(token.expect("acquire token")) + }).expect("failed to spawn helper thread") } pub fn acquire_thread() { From 7ff11d44d3a530b5ea85f8537ba54b87d955532f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 18:24:51 -0500 Subject: [PATCH 6/9] Prepare functions to run on release/acquire of a token --- src/librustc_jobserver/lib.rs | 51 +++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/librustc_jobserver/lib.rs b/src/librustc_jobserver/lib.rs index 9050346691917..ae64f30e88f30 100644 --- a/src/librustc_jobserver/lib.rs +++ b/src/librustc_jobserver/lib.rs @@ -1,5 +1,4 @@ -pub use jobserver_crate::Acquired; -use jobserver_crate::{HelperThread, Client}; +use jobserver_crate::Client; use lazy_static::lazy_static; lazy_static! { @@ -30,19 +29,61 @@ lazy_static! { }; } +// Unlike releasing tokens, there's not really a "one size fits all" approach, as we have two +// primary ways of acquiring a token: via the helper thread, and via the acquire_thread function. +// +// That makes this function necessary unlike in the release case where everything is piped through +// `release_thread`. +fn notify_acquiring_token() { + // this function does nothing for now but will be wired up to send a message to Cargo +} + pub fn initialize() { lazy_static::initialize(&GLOBAL_CLIENT) } +pub struct HelperThread { + helper: jobserver_crate::HelperThread, +} + +impl HelperThread { + // This API does not block, but is shimmed so that we can inform Cargo of our interest here. + pub fn request_token(&self) { + notify_acquiring_token(); + self.helper.request_token(); + } +} + +pub struct Acquired(()); + +impl Drop for Acquired { + fn drop(&mut self) { + release_thread(); + } +} + pub fn helper_thread(mut cb: F) -> HelperThread where F: FnMut(Acquired) + Send + 'static, { - GLOBAL_CLIENT.clone().into_helper_thread(move |token| { - cb(token.expect("acquire token")) - }).expect("failed to spawn helper thread") + let thread = GLOBAL_CLIENT.clone().into_helper_thread(move |token| { + // we've acquired a token, but we need to not use it as we have our own + // custom release-on-drop struct since we'll want different logic than + // just normally releasing the token in this case. + // + // On unix this unfortunately means that we lose the specific byte that + // was in the pipe (i.e., we just write back the same byte all the time) + // but that's not expected to be a problem. + std::mem::forget(token.expect("acquire token")); + cb(Acquired(())) + }).expect("failed to spawn helper thread"); + + HelperThread { + helper: thread, + } } pub fn acquire_thread() { + notify_acquiring_token(); GLOBAL_CLIENT.acquire_raw().ok(); } From 71fceabfd29a7cbfe54c9fe8edac7e37bb505787 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 18 Dec 2019 08:28:04 -0500 Subject: [PATCH 7/9] Track whether to emit jobserver messages This adds the -Zjobserver-token-requests debugging flag which Cargo will pass down to us, but for now that flag doesn't do anything. We don't really have a good way to deal with multiple initialize calls so for now this implementation just ignores all but the first construction's token requesting mode. It's plausible we should assert that all calls have the same mode, but it's unclear whether that really brings us any benefits (and it does have a cost of forcing people to thread things through on their end). --- src/librustc_jobserver/lib.rs | 32 ++++++++++++++++++++++++++++++-- src/librustc_session/config.rs | 2 ++ src/librustc_session/session.rs | 15 ++++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/librustc_jobserver/lib.rs b/src/librustc_jobserver/lib.rs index ae64f30e88f30..c355a8ad3b7c6 100644 --- a/src/librustc_jobserver/lib.rs +++ b/src/librustc_jobserver/lib.rs @@ -1,5 +1,6 @@ use jobserver_crate::Client; use lazy_static::lazy_static; +use std::sync::atomic::{Ordering, AtomicUsize}; lazy_static! { // We can only call `from_env` once per process @@ -35,10 +36,37 @@ lazy_static! { // That makes this function necessary unlike in the release case where everything is piped through // `release_thread`. fn notify_acquiring_token() { - // this function does nothing for now but will be wired up to send a message to Cargo + if should_notify() { + // FIXME: tell Cargo of our interest + } +} + +const EMPTY: usize = 0; +const CARGO_REQUESTED: usize = 1; +const MAKE_REQUESTED: usize = 2; +static TOKEN_REQUESTS: AtomicUsize = AtomicUsize::new(0); + +fn should_notify() -> bool { + let value = TOKEN_REQUESTS.load(Ordering::SeqCst); + assert_ne!(value, EMPTY, "jobserver must be initialized"); + value == CARGO_REQUESTED } -pub fn initialize() { +/// This changes a global value to the new value of token_requests, which means +/// that you probably don't want to be calling this more than once per process. +/// Unfortunately the jobserver is inherently a global resource (we can't have +/// more than one) so the token requesting strategy must likewise be global. +/// +/// Usually this doesn't matter too much, as you're not wanting to set the token +/// requests unless you're in the one-rustc-per-process model, and we help out +/// here a bit by not resetting it once it's set (i.e., only the first init will +/// change the value). +pub fn initialize(token_requests: bool) { + TOKEN_REQUESTS.compare_and_swap( + EMPTY, + if token_requests { CARGO_REQUESTED } else { MAKE_REQUESTED }, + Ordering::SeqCst, + ); lazy_static::initialize(&GLOBAL_CLIENT) } diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 359c8b3e73a90..091e34f45cc7a 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1570,6 +1570,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, insert_sideeffect: bool = (false, parse_bool, [TRACKED], "fix undefined behavior when a thread doesn't eventually make progress \ (such as entering an empty infinite loop) by inserting llvm.sideeffect"), + jobserver_token_requests: bool = (false, parse_bool, [UNTRACKED], + "Coordinate with caller through JSON messages on acquiring/releasing jobserver tokens"), } pub const fn default_lib_output() -> CrateType { diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 937949c91a501..cec3a00e0f3a7 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -1126,7 +1126,20 @@ fn build_session_( CguReuseTracker::new_disabled() }; - rustc_jobserver::initialize(); + if sopts.debugging_opts.jobserver_token_requests { + if let config::ErrorOutputType::Json { .. } = sopts.error_format { + if is_diagnostic_output_raw { + panic!("Raw output format not supported with -Zjobserver-token-requests"); + } + } else { + parse_sess.span_diagnostic + .fatal("-Zjobserver-token-requests can only be specified if \ + using JSON error output type") + .raise(); + } + } + + rustc_jobserver::initialize(sopts.debugging_opts.jobserver_token_requests); let sess = Session { target: target_cfg, From 3900705af736bae38409fa594bd7687a89d9662f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 18 Dec 2019 08:57:37 -0500 Subject: [PATCH 8/9] Implement jobserver event communication --- Cargo.lock | 1 + src/librustc_jobserver/Cargo.toml | 1 + src/librustc_jobserver/lib.rs | 37 +++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da3a7a84f5fe0..1f19d2a015484 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3649,6 +3649,7 @@ version = "0.0.0" dependencies = [ "jobserver", "lazy_static 1.3.0", + "serialize", ] [[package]] diff --git a/src/librustc_jobserver/Cargo.toml b/src/librustc_jobserver/Cargo.toml index 223dac54c874d..721a44a435189 100644 --- a/src/librustc_jobserver/Cargo.toml +++ b/src/librustc_jobserver/Cargo.toml @@ -12,3 +12,4 @@ doctest = false [dependencies] jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" +rustc_serialize = { path = "../libserialize", package = "serialize" } diff --git a/src/librustc_jobserver/lib.rs b/src/librustc_jobserver/lib.rs index c355a8ad3b7c6..cae5a61a499e0 100644 --- a/src/librustc_jobserver/lib.rs +++ b/src/librustc_jobserver/lib.rs @@ -1,6 +1,7 @@ use jobserver_crate::Client; use lazy_static::lazy_static; use std::sync::atomic::{Ordering, AtomicUsize}; +use rustc_serialize::json::as_json; lazy_static! { // We can only call `from_env` once per process @@ -30,17 +31,6 @@ lazy_static! { }; } -// Unlike releasing tokens, there's not really a "one size fits all" approach, as we have two -// primary ways of acquiring a token: via the helper thread, and via the acquire_thread function. -// -// That makes this function necessary unlike in the release case where everything is piped through -// `release_thread`. -fn notify_acquiring_token() { - if should_notify() { - // FIXME: tell Cargo of our interest - } -} - const EMPTY: usize = 0; const CARGO_REQUESTED: usize = 1; const MAKE_REQUESTED: usize = 2; @@ -110,11 +100,34 @@ pub fn helper_thread(mut cb: F) -> HelperThread } } +#[derive(RustcEncodable)] +enum Event { + WillAcquire, + Release, +} + +#[derive(RustcEncodable)] +struct JobserverNotification { + jobserver_event: Event, +} + +// Unlike releasing tokens, there's not really a "one size fits all" approach, as we have two +// primary ways of acquiring a token: via the helper thread, and via the acquire_thread function. +fn notify_acquiring_token() { + if should_notify() { + eprintln!("{}", as_json(&JobserverNotification { jobserver_event: Event::WillAcquire })); + } +} + pub fn acquire_thread() { notify_acquiring_token(); GLOBAL_CLIENT.acquire_raw().ok(); } pub fn release_thread() { - GLOBAL_CLIENT.release_raw().ok(); + if should_notify() { + eprintln!("{}", as_json(&JobserverNotification { jobserver_event: Event::Release })); + } else { + GLOBAL_CLIENT.release_raw().ok(); + } } From 0689914929cc8d0e7c00d82480a696fe002302be Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 18 Dec 2019 09:26:45 -0500 Subject: [PATCH 9/9] Move jobserver initialization before thread pool creation --- Cargo.lock | 1 - src/librustc_interface/interface.rs | 14 ++++++++++++++ src/librustc_session/Cargo.toml | 1 - src/librustc_session/session.rs | 15 --------------- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f19d2a015484..0341c117385ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3868,7 +3868,6 @@ dependencies = [ "rustc_feature", "rustc_fs_util", "rustc_index", - "rustc_jobserver", "rustc_target", "serialize", "syntax_pos", diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index beb2465bd4a1a..3434b08a2240b 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -181,6 +181,20 @@ pub fn run_compiler_in_existing_thread_pool( pub fn run_compiler(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { let stderr = config.stderr.take(); + + if config.opts.debugging_opts.jobserver_token_requests { + if let config::ErrorOutputType::Json { .. } = config.opts.error_format { + if stderr.is_some() { + panic!("Non-default output not supported with -Zjobserver-token-requests"); + } + } else { + panic!("-Zjobserver-token-requests can only be specified if using \ + JSON error output type"); + } + } + + rustc_jobserver::initialize(config.opts.debugging_opts.jobserver_token_requests); + util::spawn_thread_pool( config.opts.edition, config.opts.debugging_opts.threads, diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml index a0ec86f403b9f..dbbb4b92dea35 100644 --- a/src/librustc_session/Cargo.toml +++ b/src/librustc_session/Cargo.toml @@ -19,4 +19,3 @@ syntax_pos = { path = "../libsyntax_pos" } rustc_index = { path = "../librustc_index" } rustc_fs_util = { path = "../librustc_fs_util" } num_cpus = "1.0" -rustc_jobserver = { path = "../librustc_jobserver" } diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index cec3a00e0f3a7..5c0137b51c76d 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -1126,21 +1126,6 @@ fn build_session_( CguReuseTracker::new_disabled() }; - if sopts.debugging_opts.jobserver_token_requests { - if let config::ErrorOutputType::Json { .. } = sopts.error_format { - if is_diagnostic_output_raw { - panic!("Raw output format not supported with -Zjobserver-token-requests"); - } - } else { - parse_sess.span_diagnostic - .fatal("-Zjobserver-token-requests can only be specified if \ - using JSON error output type") - .raise(); - } - } - - rustc_jobserver::initialize(sopts.debugging_opts.jobserver_token_requests); - let sess = Session { target: target_cfg, host,