From bcaca33c72fe056dca2ab0d7e44ff597d653764e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Mar 2024 05:26:10 +0000 Subject: [PATCH] Give deadlock handler access to `GlobalCtxt` --- compiler/rustc_interface/src/interface.rs | 13 +++++++++++-- compiler/rustc_interface/src/queries.rs | 10 ++++++++++ compiler/rustc_interface/src/util.rs | 18 ++++++++++++------ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index cd7957c3bce29..90f76f16131a3 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -24,6 +24,7 @@ use rustc_span::symbol::sym; use rustc_span::FileName; use std::path::PathBuf; use std::result; +use std::sync::atomic::AtomicPtr; use std::sync::Arc; pub type Result = result::Result; @@ -39,6 +40,7 @@ pub struct Compiler { pub sess: Session, pub codegen_backend: Box, pub(crate) override_queries: Option, + pub compiler_for_deadlock_handler: Arc>, } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. @@ -328,9 +330,12 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); early_dcx.initialize_checked_jobserver(); + let compiler_for_deadlock_handler = Arc::>::default(); + util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, + compiler_for_deadlock_handler.clone(), || { crate::callbacks::setup_callbacks(); @@ -419,8 +424,12 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se } sess.lint_store = Some(Lrc::new(lint_store)); - let compiler = - Compiler { sess, codegen_backend, override_queries: config.override_queries }; + let compiler = Arc::new(Compiler { + sess, + codegen_backend, + override_queries: config.override_queries, + compiler_for_deadlock_handler, + }); rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || { // There are two paths out of `f`. diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 86858bfe41d81..65e14b1b3d08f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -24,6 +24,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use std::any::Any; use std::cell::{RefCell, RefMut}; +use std::sync::atomic::Ordering; use std::sync::Arc; /// Represent the result of a query. @@ -160,6 +161,10 @@ impl<'tcx> Queries<'tcx> { &self.hir_arena, ); + self.compiler + .compiler_for_deadlock_handler + .store(qcx as *const _ as *mut _, Ordering::Relaxed); + qcx.enter(|tcx| { let feed = tcx.feed_local_crate(); feed.crate_name(crate_name); @@ -311,6 +316,11 @@ impl Compiler { { // Must declare `_timer` first so that it is dropped after `queries`. let mut _timer = None; + let _guard = rustc_data_structures::defer(|| { + // If we got here, there was no deadlock, so we can't be in a situation where a deadlock handler + // is accessing the `GlobalCtxt`. + self.compiler_for_deadlock_handler.store(std::ptr::null_mut(), Ordering::Relaxed); + }); let queries = Queries::new(self); let ret = f(&queries); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 823614e1f0619..0a94af1fee489 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -18,8 +18,8 @@ use session::EarlyDiagCtxt; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::OnceLock; +use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; +use std::sync::{Arc, OnceLock}; use std::thread; /// Function pointer type that constructs a new CodegenBackend. @@ -90,6 +90,7 @@ pub(crate) fn run_in_thread_with_globals R + Send, R: Send>( pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, _threads: usize, + _compiler: Arc>, f: F, ) -> R { run_in_thread_with_globals(edition, f) @@ -99,10 +100,11 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, threads: usize, + compiler: Arc>, f: F, ) -> R { use rustc_data_structures::{jobserver, sync::FromDyn}; - use rustc_middle::ty::tls; + use rustc_middle::ty::GlobalCtxt; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::{deadlock, QueryContext}; @@ -122,11 +124,15 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) .num_threads(threads) - .deadlock_handler(|| { + .deadlock_handler(move || { + let compiler = compiler.load(Ordering::Relaxed); + assert!(!compiler.is_null()); + let compiler = compiler as *const GlobalCtxt<'_>; // On deadlock, creates a new thread and forwards information in thread // locals to it. The new thread runs the deadlock handler. - let query_map = - FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs())); + let query_map = FromDyn::from(unsafe { + (*compiler).enter(|tcx| QueryCtxt::new(tcx).collect_active_jobs()) + }); let registry = rayon_core::Registry::current(); thread::spawn(move || deadlock(query_map.into_inner(), ®istry)); });