Skip to content

Commit

Permalink
Rollup merge of rust-lang#23651 - alexcrichton:unwind-try, r=aturon
Browse files Browse the repository at this point in the history
 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.
  • Loading branch information
Manishearth committed Mar 26, 2015
2 parents 4c06f3e + 4c2ddb3 commit b8768a1
Showing 1 changed file with 49 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,55 @@ pub fn panicking() -> bool {
unwind::panicking()
}

/// Invoke a closure, capturing the cause of panic if one occurs.
///
/// This function will return `Ok(())` if the closure does not panic, and will
/// return `Err(cause)` if the closure panics. The `cause` returned is the
/// object with which panic was originally invoked.
///
/// It is currently undefined behavior to unwind from Rust code into foreign
/// code, so this function is particularly useful when Rust is called from
/// another language (normally C). This can run arbitrary Rust code, capturing a
/// panic and allowing a graceful handling of the error.
///
/// It is **not** recommended to use this function for a general try/catch
/// mechanism. The `Result` type is more appropriate to use for functions that
/// can fail on a regular basis.
///
/// The closure provided is required to adhere to the `'static` bound to ensure
/// that it cannot reference data in the parent stack frame, mitigating problems
/// with exception safety. Furthermore, a `Send` bound is also required,
/// providing the same safety guarantees as `thread::spawn` (ensuring the
/// closure is properly isolated from the parent).
///
/// # Examples
///
/// ```
/// # #![feature(catch_panic)]
/// use std::thread;
///
/// let result = thread::catch_panic(|| {
/// println!("hello!");
/// });
/// assert!(result.is_ok());
///
/// let result = thread::catch_panic(|| {
/// panic!("oh no!");
/// });
/// assert!(result.is_err());
/// ```
#[unstable(feature = "catch_panic", reason = "recent API addition")]
pub fn catch_panic<F, R>(f: F) -> Result<R>
where F: FnOnce() -> R + Send + 'static
{
let mut result = None;
unsafe {
let result = &mut result;
try!(::rt::unwind::try(move || *result = Some(f())))
}
Ok(result.unwrap())
}

/// Put the current thread to sleep for the specified amount of time.
///
/// The thread may sleep longer than the duration specified due to scheduling
Expand Down

0 comments on commit b8768a1

Please sign in to comment.