Skip to content

Commit fea1f78

Browse files
rycarllerche
authored andcommitted
threadpool: add panic_handler (#1052)
1 parent 712ca84 commit fea1f78

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

tokio-threadpool/src/builder.rs

+30
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use shutdown::ShutdownTrigger;
66
use thread_pool::ThreadPool;
77
use worker::{self, Worker, WorkerId};
88

9+
use std::any::Any;
910
use std::cmp::max;
1011
use std::error::Error;
1112
use std::fmt;
@@ -106,6 +107,7 @@ impl Builder {
106107
around_worker: None,
107108
after_start: None,
108109
before_stop: None,
110+
panic_handler: None,
109111
},
110112
new_park,
111113
}
@@ -199,6 +201,34 @@ impl Builder {
199201
self
200202
}
201203

204+
/// Sets a callback to be triggered when a panic during a future bubbles up
205+
/// to Tokio. By default Tokio catches these panics, and they will be
206+
/// ignored. The parameter passed to this callback is the same error value
207+
/// returned from std::panic::catch_unwind(). To abort the process on
208+
/// panics, use std::panic::resume_unwind() in this callback as shown
209+
/// below.
210+
///
211+
/// # Examples
212+
///
213+
/// ```
214+
/// # extern crate tokio_threadpool;
215+
/// # extern crate futures;
216+
/// # use tokio_threadpool::Builder;
217+
///
218+
/// # pub fn main() {
219+
/// let thread_pool = Builder::new()
220+
/// .panic_handler(|err| std::panic::resume_unwind(err))
221+
/// .build();
222+
/// # }
223+
/// ```
224+
pub fn panic_handler<F>(&mut self, f: F) -> &mut Self
225+
where
226+
F: Fn(Box<Any + Send>) + Send + Sync + 'static,
227+
{
228+
self.config.panic_handler = Some(Arc::new(f));
229+
self
230+
}
231+
202232
/// Set name prefix of threads spawned by the scheduler
203233
///
204234
/// Thread name prefix is used for generating thread names. For example, if

tokio-threadpool/src/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use callback::Callback;
22

3+
use std::any::Any;
34
use std::fmt;
45
use std::sync::Arc;
56
use std::time::Duration;
@@ -14,6 +15,7 @@ pub(crate) struct Config {
1415
pub around_worker: Option<Callback>,
1516
pub after_start: Option<Arc<Fn() + Send + Sync>>,
1617
pub before_stop: Option<Arc<Fn() + Send + Sync>>,
18+
pub panic_handler: Option<Arc<Fn(Box<Any + Send>) + Send + Sync>>,
1719
}
1820

1921
/// Max number of workers that can be part of a pool. This is the most that can

tokio-threadpool/src/task/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ impl Task {
165165
// Transition to the completed state
166166
self.state.store(State::Complete.into(), Release);
167167

168+
if let Err(panic_err) = res {
169+
if let Some(ref f) = unpark.pool.config.panic_handler {
170+
f(panic_err);
171+
}
172+
}
173+
168174
Run::Complete
169175
}
170176
Ok(Ok(Async::NotReady)) => {

tokio-threadpool/tests/threadpool.rs

+17
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,23 @@ fn panic_in_task() {
399399
pool.shutdown_on_idle().wait().unwrap();
400400
}
401401

402+
#[test]
403+
fn count_panics() {
404+
let counter = Arc::new(AtomicUsize::new(0));
405+
let counter_ = counter.clone();
406+
let pool = tokio_threadpool::Builder::new()
407+
.panic_handler(move |_err| {
408+
// We caught a panic.
409+
counter_.fetch_add(1, Relaxed);
410+
})
411+
.build();
412+
// Spawn a future that will panic.
413+
pool.spawn(lazy(|| -> Result<(), ()> { panic!() }));
414+
pool.shutdown_on_idle().wait().unwrap();
415+
let counter = counter.load(Relaxed);
416+
assert_eq!(counter, 1);
417+
}
418+
402419
#[test]
403420
fn multi_threadpool() {
404421
use futures::sync::oneshot;

0 commit comments

Comments
 (0)