@@ -25,8 +25,18 @@ impl ConcurrencyLimiter {
25
25
. clone ( )
26
26
. into_helper_thread ( move |token| {
27
27
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
+ }
30
40
} )
31
41
. unwrap ( ) ;
32
42
ConcurrencyLimiter {
@@ -37,16 +47,31 @@ impl ConcurrencyLimiter {
37
47
}
38
48
}
39
49
40
- pub ( super ) fn acquire ( & mut self ) -> ConcurrencyLimiterToken {
50
+ pub ( super ) fn acquire ( & mut self , handler : & rustc_errors :: Handler ) -> ConcurrencyLimiterToken {
41
51
let mut state = self . state . lock ( ) . unwrap ( ) ;
42
52
loop {
43
53
state. assert_invariants ( ) ;
44
54
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
+ }
50
75
}
51
76
52
77
self . helper_thread . as_mut ( ) . unwrap ( ) . request_token ( ) ;
@@ -100,13 +125,22 @@ mod state {
100
125
pending_jobs : usize ,
101
126
active_jobs : usize ,
102
127
128
+ poisoned : bool ,
129
+ stored_error : Option < String > ,
130
+
103
131
// None is used to represent the implicit token, Some to represent explicit tokens
104
132
tokens : Vec < Option < Acquired > > ,
105
133
}
106
134
107
135
impl ConcurrencyLimiterState {
108
136
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
+ }
110
144
}
111
145
112
146
pub ( super ) fn assert_invariants ( & self ) {
@@ -127,14 +161,18 @@ mod state {
127
161
self . drop_excess_capacity ( ) ;
128
162
}
129
163
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
+
131
169
if self . active_jobs < self . tokens . len ( ) {
132
170
// Using existing token
133
171
self . job_started ( ) ;
134
- return true ;
172
+ return Ok ( true ) ;
135
173
}
136
174
137
- false
175
+ Ok ( false )
138
176
}
139
177
140
178
pub ( super ) fn job_started ( & mut self ) {
@@ -161,6 +199,11 @@ mod state {
161
199
self . assert_invariants ( ) ;
162
200
}
163
201
202
+ pub ( super ) fn poison ( & mut self , error : String ) {
203
+ self . poisoned = true ;
204
+ self . stored_error = Some ( error) ;
205
+ }
206
+
164
207
fn drop_excess_capacity ( & mut self ) {
165
208
self . assert_invariants ( ) ;
166
209
0 commit comments