Skip to content

Commit 4c2ddb3

Browse files
committedMar 24, 2015
std: Reexport std::rt::unwind::try in std::thread
This commit provides a safe, but unstable interface for the `try` functionality of running a closure and determining whether it panicked or not. There are two primary reasons that this function was previously marked `unsafe`: 1. A vanilla version of this function exposes the problem of exception safety by allowing a bare try/catch in the language. It is not clear whether this concern should be directly tied to `unsafe` in Rust at the API level. At this time, however, the bounds on `ffi::try` require the closure to be both `'static` and `Send` (mirroring those of `thread::spawn`). It may be possible to relax the bounds in the future, but for now it's the level of safety that we're willing to commit to. 2. Panicking while panicking will leak resources by not running destructors. Because panicking is still controlled by the standard library, safeguards remain in place to prevent this from happening. The new API is now called `catch_panic` and is marked as `#[unstable]` for now.
1 parent ed81038 commit 4c2ddb3

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed
 

‎src/libstd/thread/mod.rs

+49
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,55 @@ pub fn panicking() -> bool {
434434
unwind::panicking()
435435
}
436436

437+
/// Invoke a closure, capturing the cause of panic if one occurs.
438+
///
439+
/// This function will return `Ok(())` if the closure does not panic, and will
440+
/// return `Err(cause)` if the closure panics. The `cause` returned is the
441+
/// object with which panic was originally invoked.
442+
///
443+
/// It is currently undefined behavior to unwind from Rust code into foreign
444+
/// code, so this function is particularly useful when Rust is called from
445+
/// another language (normally C). This can run arbitrary Rust code, capturing a
446+
/// panic and allowing a graceful handling of the error.
447+
///
448+
/// It is **not** recommended to use this function for a general try/catch
449+
/// mechanism. The `Result` type is more appropriate to use for functions that
450+
/// can fail on a regular basis.
451+
///
452+
/// The closure provided is required to adhere to the `'static` bound to ensure
453+
/// that it cannot reference data in the parent stack frame, mitigating problems
454+
/// with exception safety. Furthermore, a `Send` bound is also required,
455+
/// providing the same safety guarantees as `thread::spawn` (ensuring the
456+
/// closure is properly isolated from the parent).
457+
///
458+
/// # Examples
459+
///
460+
/// ```
461+
/// # #![feature(catch_panic)]
462+
/// use std::thread;
463+
///
464+
/// let result = thread::catch_panic(|| {
465+
/// println!("hello!");
466+
/// });
467+
/// assert!(result.is_ok());
468+
///
469+
/// let result = thread::catch_panic(|| {
470+
/// panic!("oh no!");
471+
/// });
472+
/// assert!(result.is_err());
473+
/// ```
474+
#[unstable(feature = "catch_panic", reason = "recent API addition")]
475+
pub fn catch_panic<F, R>(f: F) -> Result<R>
476+
where F: FnOnce() -> R + Send + 'static
477+
{
478+
let mut result = None;
479+
unsafe {
480+
let result = &mut result;
481+
try!(::rt::unwind::try(move || *result = Some(f())))
482+
}
483+
Ok(result.unwrap())
484+
}
485+
437486
/// Put the current thread to sleep for the specified amount of time.
438487
///
439488
/// The thread may sleep longer than the duration specified due to scheduling

0 commit comments

Comments
 (0)
Please sign in to comment.