Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9970b04

Browse files
committed
Don't deadlock when failing to acquire a jobserver token
1 parent fd4e1d5 commit 9970b04

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed

src/concurrency_limiter.rs

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,18 @@ impl ConcurrencyLimiter {
2525
.clone()
2626
.into_helper_thread(move |token| {
2727
let mut state = state_helper.lock().unwrap();
28-
state.add_new_token(token.unwrap());
29-
available_token_condvar_helper.notify_one();
28+
match token {
29+
Ok(token) => {
30+
state.add_new_token(token);
31+
available_token_condvar_helper.notify_one();
32+
}
33+
Err(err) => {
34+
state.poison(format!("failed to acquire jobserver token: {}", err));
35+
// Notify all threads waiting for a token to give them a chance to
36+
// gracefully exit.
37+
available_token_condvar_helper.notify_all();
38+
}
39+
}
3040
})
3141
.unwrap();
3242
ConcurrencyLimiter {
@@ -37,16 +47,31 @@ impl ConcurrencyLimiter {
3747
}
3848
}
3949

40-
pub(super) fn acquire(&mut self) -> ConcurrencyLimiterToken {
50+
pub(super) fn acquire(&mut self, handler: &rustc_errors::Handler) -> ConcurrencyLimiterToken {
4151
let mut state = self.state.lock().unwrap();
4252
loop {
4353
state.assert_invariants();
4454

45-
if state.try_start_job() {
46-
return ConcurrencyLimiterToken {
47-
state: self.state.clone(),
48-
available_token_condvar: self.available_token_condvar.clone(),
49-
};
55+
match state.try_start_job() {
56+
Ok(true) => {
57+
return ConcurrencyLimiterToken {
58+
state: self.state.clone(),
59+
available_token_condvar: self.available_token_condvar.clone(),
60+
};
61+
}
62+
Ok(false) => {}
63+
Err(err) => {
64+
// An error happened when acquiring the token. Raise it as fatal error.
65+
// Make sure to drop the mutex guard first to prevent poisoning the mutex.
66+
drop(state);
67+
if let Some(err) = err {
68+
handler.fatal(&err).raise();
69+
} else {
70+
// The error was already emitted, but compilation continued. Raise a silent
71+
// fatal error.
72+
rustc_errors::FatalError.raise();
73+
}
74+
}
5075
}
5176

5277
self.helper_thread.as_mut().unwrap().request_token();
@@ -100,13 +125,22 @@ mod state {
100125
pending_jobs: usize,
101126
active_jobs: usize,
102127

128+
poisoned: bool,
129+
stored_error: Option<String>,
130+
103131
// None is used to represent the implicit token, Some to represent explicit tokens
104132
tokens: Vec<Option<Acquired>>,
105133
}
106134

107135
impl ConcurrencyLimiterState {
108136
pub(super) fn new(pending_jobs: usize) -> Self {
109-
ConcurrencyLimiterState { pending_jobs, active_jobs: 0, tokens: vec![None] }
137+
ConcurrencyLimiterState {
138+
pending_jobs,
139+
active_jobs: 0,
140+
poisoned: false,
141+
stored_error: None,
142+
tokens: vec![None],
143+
}
110144
}
111145

112146
pub(super) fn assert_invariants(&self) {
@@ -127,14 +161,18 @@ mod state {
127161
self.drop_excess_capacity();
128162
}
129163

130-
pub(super) fn try_start_job(&mut self) -> bool {
164+
pub(super) fn try_start_job(&mut self) -> Result<bool, Option<String>> {
165+
if self.poisoned {
166+
return Err(self.stored_error.take());
167+
}
168+
131169
if self.active_jobs < self.tokens.len() {
132170
// Using existing token
133171
self.job_started();
134-
return true;
172+
return Ok(true);
135173
}
136174

137-
false
175+
Ok(false)
138176
}
139177

140178
pub(super) fn job_started(&mut self) {
@@ -161,6 +199,11 @@ mod state {
161199
self.assert_invariants();
162200
}
163201

202+
pub(super) fn poison(&mut self, error: String) {
203+
self.poisoned = true;
204+
self.stored_error = Some(error);
205+
}
206+
164207
fn drop_excess_capacity(&mut self) {
165208
self.assert_invariants();
166209

src/driver/aot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ pub(crate) fn run_aot(
407407
backend_config.clone(),
408408
global_asm_config.clone(),
409409
cgu.name(),
410-
concurrency_limiter.acquire(),
410+
concurrency_limiter.acquire(tcx.sess.diagnostic()),
411411
),
412412
module_codegen,
413413
Some(rustc_middle::dep_graph::hash_result),

0 commit comments

Comments
 (0)