@@ -83,6 +83,7 @@ use std::env;
83
83
use std:: fmt;
84
84
use std:: io:: { self , Read , Seek , SeekFrom , Write } ;
85
85
use std:: mem;
86
+ use std:: num:: NonZeroUsize ;
86
87
use std:: panic;
87
88
use std:: pin:: Pin ;
88
89
use std:: slice;
@@ -120,9 +121,6 @@ struct Executor {
120
121
121
122
/// Used to put idle threads to sleep and wake them up when new work comes in.
122
123
cvar : Condvar ,
123
-
124
- /// Maximum number of threads in the pool
125
- thread_limit : usize ,
126
124
}
127
125
128
126
/// Inner state of the blocking executor.
@@ -139,6 +137,9 @@ struct Inner {
139
137
140
138
/// The queue of blocking tasks.
141
139
queue : VecDeque < Runnable > ,
140
+
141
+ /// Maximum number of threads in the pool
142
+ thread_limit : NonZeroUsize ,
142
143
}
143
144
144
145
impl Executor {
@@ -167,9 +168,9 @@ impl Executor {
167
168
idle_count : 0 ,
168
169
thread_count : 0 ,
169
170
queue : VecDeque :: new ( ) ,
171
+ thread_limit : NonZeroUsize :: new ( thread_limit) . unwrap ( ) ,
170
172
} ) ,
171
173
cvar : Condvar :: new ( ) ,
172
- thread_limit,
173
174
}
174
175
} ) ;
175
176
@@ -232,7 +233,9 @@ impl Executor {
232
233
fn grow_pool ( & ' static self , mut inner : MutexGuard < ' static , Inner > ) {
233
234
// If runnable tasks greatly outnumber idle threads and there aren't too many threads
234
235
// already, then be aggressive: wake all idle threads and spawn one more thread.
235
- while inner. queue . len ( ) > inner. idle_count * 5 && inner. thread_count < self . thread_limit {
236
+ while inner. queue . len ( ) > inner. idle_count * 5
237
+ && inner. thread_count < inner. thread_limit . get ( )
238
+ {
236
239
// The new thread starts in idle state.
237
240
inner. idle_count += 1 ;
238
241
inner. thread_count += 1 ;
@@ -245,10 +248,25 @@ impl Executor {
245
248
let id = ID . fetch_add ( 1 , Ordering :: Relaxed ) ;
246
249
247
250
// Spawn the new thread.
248
- thread:: Builder :: new ( )
251
+ if let Err ( e ) = thread:: Builder :: new ( )
249
252
. name ( format ! ( "blocking-{}" , id) )
250
253
. spawn ( move || self . main_loop ( ) )
251
- . unwrap ( ) ;
254
+ {
255
+ // We were unable to spawn the thread, so we need to undo the state changes.
256
+ log:: error!( "Failed to spawn a blocking thread: {}" , e) ;
257
+ inner. idle_count -= 1 ;
258
+ inner. thread_count -= 1 ;
259
+
260
+ // The current number of threads is likely to be the system's upper limit, so update
261
+ // thread_limit accordingly.
262
+ inner. thread_limit = {
263
+ let new_limit = inner. thread_count ;
264
+
265
+ // If the limit is about to be set to zero, set it to one instead so that if,
266
+ // in the future, we are able to spawn more threads, we will be able to do so.
267
+ NonZeroUsize :: new ( new_limit) . unwrap_or_else ( || NonZeroUsize :: new ( 1 ) . unwrap ( ) )
268
+ } ;
269
+ }
252
270
}
253
271
}
254
272
}
0 commit comments