From c60e5614e1f366f638a45d34291f0249ff1805a5 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Wed, 29 Apr 2026 15:18:21 +0300 Subject: [PATCH] rustc: Avoid passing jobserver proxy around the compiler It is used once, when marking a `rustc_thread_pool` worker thread as blocked. `rustc_thread_pool` already has access to the jobserver proxy, so we can move its use from outside of `mark_blocked` to inside of it. --- compiler/rustc_interface/src/interface.rs | 8 ++------ compiler/rustc_interface/src/passes.rs | 1 - compiler/rustc_interface/src/util.rs | 22 +++++++++------------- compiler/rustc_middle/src/query/job.rs | 19 ++++++------------- compiler/rustc_middle/src/ty/context.rs | 6 ------ compiler/rustc_query_impl/src/execution.rs | 2 +- compiler/rustc_thread_pool/src/lib.rs | 2 +- compiler/rustc_thread_pool/src/registry.rs | 9 ++++++--- 8 files changed, 25 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 95aeb1f7a234f..6a1cd915d1b48 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::jobserver::{self, Proxy}; +use rustc_data_structures::jobserver; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_lint::LintStore; use rustc_middle::ty; @@ -41,9 +41,6 @@ pub struct Compiler { /// A reference to the current `GlobalCtxt` which we pass on to `GlobalCtxt`. pub(crate) current_gcx: CurrentGcx, - - /// A jobserver reference which we pass on to `GlobalCtxt`. - pub(crate) jobserver_proxy: Arc, } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. @@ -412,7 +409,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.opts.unstable_opts.threads.unwrap_or(1), &config.extra_symbols, SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, - |current_gcx, jobserver_proxy| { + |current_gcx| { // The previous `early_dcx` can't be reused here because it doesn't // impl `Send`. Creating a new one is fine. let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); @@ -485,7 +482,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se codegen_backend, override_queries: config.override_queries, current_gcx, - jobserver_proxy, }; // There are two paths out of `f`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ca983db29bcf7..3bb9e48e3b995 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1010,7 +1010,6 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( ), providers.hooks, compiler.current_gcx.clone(), - Arc::clone(&compiler.jobserver_proxy), |tcx| { let feed = tcx.create_crate_num(stable_crate_id).unwrap(); assert_eq!(feed.key(), LOCAL_CRATE); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index c78e419033d78..39c5ee8193256 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -133,7 +133,7 @@ fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize { }) } -fn run_in_thread_with_globals) -> R + Send, R: Send>( +fn run_in_thread_with_globals R + Send, R: Send>( thread_stack_size: usize, edition: Edition, sm_inputs: SourceMapInputs, @@ -159,7 +159,7 @@ fn run_in_thread_with_globals) -> R + Send, R: edition, extra_symbols, Some(sm_inputs), - || f(CurrentGcx::new(), Proxy::new()), + || f(CurrentGcx::new()), ) }) .unwrap() @@ -172,10 +172,7 @@ fn run_in_thread_with_globals) -> R + Send, R: }) } -pub(crate) fn run_in_thread_pool_with_globals< - F: FnOnce(CurrentGcx, Arc) -> R + Send, - R: Send, ->( +pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( thread_builder_diag: &EarlyDiagCtxt, edition: Edition, threads: usize, @@ -199,11 +196,11 @@ pub(crate) fn run_in_thread_pool_with_globals< edition, sm_inputs, extra_symbols, - |current_gcx, jobserver_proxy| { + |current_gcx| { // Register the thread for use with the `WorkerLocal` type. registry.register(); - f(current_gcx, jobserver_proxy) + f(current_gcx) }, ); }; @@ -212,13 +209,12 @@ pub(crate) fn run_in_thread_pool_with_globals< let current_gcx2 = current_gcx.clone(); let proxy = Proxy::new(); - let proxy_ = Arc::clone(&proxy); - let proxy__ = Arc::clone(&proxy); + let builder = rustc_thread_pool::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) - .acquire_thread_handler(move || proxy_.acquire_thread()) - .release_thread_handler(move || proxy__.release_thread()) + .acquire_thread_handler(move || proxy.acquire_thread()) + .release_thread_handler(move || proxy_.release_thread()) .num_threads(threads) .deadlock_handler(move || { // On deadlock, creates a new thread and forwards information in thread @@ -294,7 +290,7 @@ internal compiler error: query cycle handler thread panicked, aborting process"; }, // Run `f` on the first thread in the thread pool. move |pool: &rustc_thread_pool::ThreadPool| { - pool.install(|| f(current_gcx.into_inner(), proxy)) + pool.install(|| f(current_gcx.into_inner())) }, ) .unwrap_or_else(|err| { diff --git a/compiler/rustc_middle/src/query/job.rs b/compiler/rustc_middle/src/query/job.rs index 8c78bf24287e0..7f48b2dbdbb22 100644 --- a/compiler/rustc_middle/src/query/job.rs +++ b/compiler/rustc_middle/src/query/job.rs @@ -7,7 +7,6 @@ use parking_lot::{Condvar, Mutex}; use rustc_span::Span; use crate::query::Cycle; -use crate::ty::TyCtxt; /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] @@ -71,12 +70,7 @@ impl<'tcx> QueryLatch<'tcx> { } /// Awaits for the query job to complete. - pub fn wait_on( - &self, - tcx: TyCtxt<'tcx>, - query: Option, - span: Span, - ) -> Result<(), Cycle<'tcx>> { + pub fn wait_on(&self, query: Option, span: Span) -> Result<(), Cycle<'tcx>> { let mut waiters_guard = self.waiters.lock(); let Some(waiters) = &mut *waiters_guard else { return Ok(()); // already complete @@ -99,12 +93,11 @@ impl<'tcx> QueryLatch<'tcx> { // If this detects a deadlock and the deadlock handler wants to resume this thread // we have to be in the `wait` call. This is ensured by the deadlock handler // getting the self.info lock. - rustc_thread_pool::mark_blocked(); - tcx.jobserver_proxy.release_thread(); - waiter.condvar.wait(&mut waiters_guard); - // Release the lock before we potentially block in `acquire_thread` - drop(waiters_guard); - tcx.jobserver_proxy.acquire_thread(); + rustc_thread_pool::mark_blocked_and_wait(|| { + waiter.condvar.wait(&mut waiters_guard); + // Release the lock before we potentially block when acquiring jobserver token. + drop(waiters_guard); + }); // FIXME: Get rid of this lock. We have ownership of the QueryWaiter // although another thread may still have a Arc reference so we cannot diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 146662676acc0..633466102817b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -20,7 +20,6 @@ use rustc_ast as ast; use rustc_data_structures::defer; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; -use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hash::StableHash; @@ -767,9 +766,6 @@ pub struct GlobalCtxt<'tcx> { pub(crate) alloc_map: interpret::AllocMap<'tcx>, current_gcx: CurrentGcx, - - /// A jobserver reference used to release then acquire a token while waiting on a query. - pub jobserver_proxy: Arc, } impl<'tcx> GlobalCtxt<'tcx> { @@ -944,7 +940,6 @@ impl<'tcx> TyCtxt<'tcx> { query_system: QuerySystem<'tcx>, hooks: crate::hooks::Providers, current_gcx: CurrentGcx, - jobserver_proxy: Arc, f: impl FnOnce(TyCtxt<'tcx>) -> T, ) -> T { let data_layout = sess.target.parse_data_layout().unwrap_or_else(|err| { @@ -982,7 +977,6 @@ impl<'tcx> TyCtxt<'tcx> { data_layout, alloc_map: interpret::AllocMap::new(), current_gcx, - jobserver_proxy, }); // This is a separate function to work around a crash with parallel rustc (#135870) diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 5b59f005a4908..22cdc30a4ae86 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -252,7 +252,7 @@ fn wait_for_query<'tcx, C: QueryCache>( let query_blocked_prof_timer = tcx.prof.query_blocked(); // With parallel queries we might just have to wait on some other thread. - let result = latch.wait_on(tcx, current, span); + let result = latch.wait_on(current, span); match result { Ok(()) => { diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs index 7ce7fbc27eabe..56d3bc1184454 100644 --- a/compiler/rustc_thread_pool/src/lib.rs +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -95,7 +95,7 @@ pub use worker_local::WorkerLocal; pub use self::broadcast::{BroadcastContext, broadcast, spawn_broadcast}; pub use self::join::{join, join_context}; use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn}; -pub use self::registry::{Registry, ThreadBuilder, mark_blocked, mark_unblocked}; +pub use self::registry::{Registry, ThreadBuilder, mark_blocked_and_wait, mark_unblocked}; pub use self::scope::{Scope, ScopeFifo, in_place_scope, in_place_scope_fifo, scope, scope_fifo}; pub use self::spawn::{spawn, spawn_fifo}; pub use self::thread_pool::{ diff --git a/compiler/rustc_thread_pool/src/registry.rs b/compiler/rustc_thread_pool/src/registry.rs index 9510c1842f86a..71b2e11f7a8cd 100644 --- a/compiler/rustc_thread_pool/src/registry.rs +++ b/compiler/rustc_thread_pool/src/registry.rs @@ -615,14 +615,17 @@ impl Registry { } /// Mark a Rayon worker thread as blocked. This triggers the deadlock handler -/// if no other worker thread is active +/// if no other worker thread is active. Then wait for the user-specified condition. #[inline] -pub fn mark_blocked() { +pub fn mark_blocked_and_wait(wait: impl FnOnce()) { let worker_thread = WorkerThread::current(); assert!(!worker_thread.is_null()); unsafe { let registry = &(*worker_thread).registry; - registry.sleep.mark_blocked(®istry.deadlock_handler) + registry.sleep.mark_blocked(®istry.deadlock_handler); + registry.release_thread(); + wait(); + registry.acquire_thread(); } }