Skip to content

Commit cf13d91

Browse files
committed
Clarify run_in_thread_pool_with_globals.
- Make the structure of the two variants more similar. - Add some comments. - Move various conditional `use` items inside the function that uses them. - Inline some closures.
1 parent 2efc90e commit cf13d91

File tree

2 files changed

+46
-44
lines changed

2 files changed

+46
-44
lines changed

compiler/rustc_driver/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
190190
run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
191191
}
192192
}
193+
193194
fn run_compiler(
194195
at_args: &[String],
195196
callbacks: &mut (dyn Callbacks + Send),

compiler/rustc_interface/src/util.rs

+45-44
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,8 @@ use libloading::Library;
33
use rustc_ast as ast;
44
use rustc_codegen_ssa::traits::CodegenBackend;
55
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
6-
#[cfg(parallel_compiler)]
7-
use rustc_data_structures::jobserver;
86
use rustc_errors::registry::Registry;
9-
#[cfg(parallel_compiler)]
10-
use rustc_middle::ty::tls;
117
use rustc_parse::validate_attr;
12-
#[cfg(parallel_compiler)]
13-
use rustc_query_impl::{QueryContext, QueryCtxt};
148
use rustc_session as session;
159
use rustc_session::config::CheckCfg;
1610
use rustc_session::config::{self, CrateType};
@@ -25,8 +19,6 @@ use rustc_span::symbol::{sym, Symbol};
2519
use std::env;
2620
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
2721
use std::mem;
28-
#[cfg(not(parallel_compiler))]
29-
use std::panic;
3022
use std::path::{Path, PathBuf};
3123
use std::sync::atomic::{AtomicBool, Ordering};
3224
use std::sync::OnceLock;
@@ -135,13 +127,20 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
135127
_threads: usize,
136128
f: F,
137129
) -> R {
138-
// The thread pool is a single thread in the non-parallel compiler.
139-
thread::scope(|s| {
140-
let mut builder = thread::Builder::new().name("rustc".to_string());
141-
if let Some(size) = get_stack_size() {
142-
builder = builder.stack_size(size);
143-
}
130+
// The "thread pool" is a single spawned thread in the non-parallel
131+
// compiler. We run on a spawned thread instead of the main thread (a) to
132+
// provide control over the stack size, and (b) to increase similarity with
133+
// the parallel compiler, in particular to ensure there is no accidental
134+
// sharing of data between the main thread and the compilation thread
135+
// (which might cause problems for the parallel compiler).
136+
let mut builder = thread::Builder::new().name("rustc".to_string());
137+
if let Some(size) = get_stack_size() {
138+
builder = builder.stack_size(size);
139+
}
144140

141+
// We build the session globals and run `f` on the spawned thread, because
142+
// `SessionGlobals` does not impl `Send` in the non-parallel compiler.
143+
thread::scope(|s| {
145144
// `unwrap` is ok here because `spawn_scoped` only panics if the thread
146145
// name contains null bytes.
147146
let r = builder
@@ -151,55 +150,57 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
151150

152151
match r {
153152
Ok(v) => v,
154-
Err(e) => panic::resume_unwind(e),
153+
Err(e) => std::panic::resume_unwind(e),
155154
}
156155
})
157156
}
158157

159-
/// Creates a new thread and forwards information in thread locals to it.
160-
/// The new thread runs the deadlock handler.
161-
/// Must only be called when a deadlock is about to happen.
162-
#[cfg(parallel_compiler)]
163-
unsafe fn handle_deadlock() {
164-
let registry = rustc_rayon_core::Registry::current();
165-
166-
let query_map = tls::with(|tcx| {
167-
QueryCtxt::from_tcx(tcx)
168-
.try_collect_active_jobs()
169-
.expect("active jobs shouldn't be locked in deadlock handler")
170-
});
171-
thread::spawn(move || rustc_query_impl::deadlock(query_map, &registry));
172-
}
173-
174158
#[cfg(parallel_compiler)]
175159
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
176160
edition: Edition,
177161
threads: usize,
178162
f: F,
179163
) -> R {
180-
let mut config = rayon::ThreadPoolBuilder::new()
164+
use rustc_data_structures::jobserver;
165+
use rustc_middle::ty::tls;
166+
use rustc_query_impl::{deadlock, QueryContext, QueryCtxt};
167+
168+
let mut builder = rayon::ThreadPoolBuilder::new()
181169
.thread_name(|_| "rustc".to_string())
182170
.acquire_thread_handler(jobserver::acquire_thread)
183171
.release_thread_handler(jobserver::release_thread)
184172
.num_threads(threads)
185-
.deadlock_handler(|| unsafe { handle_deadlock() });
186-
173+
.deadlock_handler(|| {
174+
// On deadlock, creates a new thread and forwards information in thread
175+
// locals to it. The new thread runs the deadlock handler.
176+
let query_map = tls::with(|tcx| {
177+
QueryCtxt::from_tcx(tcx)
178+
.try_collect_active_jobs()
179+
.expect("active jobs shouldn't be locked in deadlock handler")
180+
});
181+
let registry = rustc_rayon_core::Registry::current();
182+
thread::spawn(move || deadlock(query_map, &registry));
183+
});
187184
if let Some(size) = get_stack_size() {
188-
config = config.stack_size(size);
185+
builder = builder.stack_size(size);
189186
}
190187

191-
let with_pool = move |pool: &rayon::ThreadPool| pool.install(f);
192-
188+
// We create the session globals on the main thread, then create the thread
189+
// pool. Upon creation, each worker thread created gets a copy of the
190+
// session globals in TLS. This is possible because `SessionGlobals` impls
191+
// `Send` in the parallel compiler.
193192
rustc_span::create_session_globals_then(edition, || {
194193
rustc_span::with_session_globals(|session_globals| {
195-
// The main handler runs for each Rayon worker thread and sets up
196-
// the thread local rustc uses. `session_globals` is captured and set
197-
// on the new threads.
198-
let main_handler = move |thread: rayon::ThreadBuilder| {
199-
rustc_span::set_session_globals_then(session_globals, || thread.run())
200-
};
201-
202-
config.build_scoped(main_handler, with_pool).unwrap()
194+
builder
195+
.build_scoped(
196+
// Initialize each new worker thread when created.
197+
move |thread: rayon::ThreadBuilder| {
198+
rustc_span::set_session_globals_then(session_globals, || thread.run())
199+
},
200+
// Run `f` on the first thread in the thread pool.
201+
move |pool: &rayon::ThreadPool| pool.install(f),
202+
)
203+
.unwrap()
203204
})
204205
})
205206
}

0 commit comments

Comments
 (0)