Skip to content

Commit

Permalink
Clarify catch_unwind behavior of RemoteHandle. (rust-lang#2080)
Browse files Browse the repository at this point in the history
  • Loading branch information
najamelan committed Feb 13, 2020
1 parent c743c53 commit c8f3919
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions futures-util/src/future/future/remote_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ use {
/// The handle to a remote future returned by
/// [`remote_handle`](crate::future::FutureExt::remote_handle). When you drop this,
/// the remote future will be woken up to be dropped by the executor.
///
/// ## Unwind safety
///
/// When the remote future panics, [Remote] will catch the unwind and transfer it to
/// the thread where `RemoteHandle` is being awaited. This is good for the common
/// case where [Remote] is spawned on a threadpool. It is unlikely that other code
/// in the executor working thread shares mutable data with the spawned future and we
/// preserve the executor from losing its working threads.
///
/// If you run the future locally and send the handle of to be awaited elsewhere, you
/// must be careful with regard to unwind safety because the thread in which the future
/// is polled will keep running after the panic and the thread running the [RemoteHandle]
/// will unwind.
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
pub struct RemoteHandle<T> {
Expand All @@ -45,7 +58,9 @@ impl<T: Send + 'static> Future for RemoteHandle<T> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
match ready!(self.rx.poll_unpin(cx)) {
Ok(Ok(output)) => Poll::Ready(output),
// the remote future panicked.
Ok(Err(e)) => panic::resume_unwind(e),
// The oneshot sender was dropped.
Err(e) => panic::resume_unwind(Box::new(e)),
}
}
Expand Down Expand Up @@ -101,9 +116,7 @@ pub(super) fn remote_handle<Fut: Future>(future: Fut) -> (Remote<Fut>, RemoteHan
let (tx, rx) = oneshot::channel();
let keep_running = Arc::new(AtomicBool::new(false));

// AssertUnwindSafe is used here because `Send + 'static` is basically
// an alias for an implementation of the `UnwindSafe` trait but we can't
// express that in the standard library right now.
// Unwind Safety: See the docs for RemoteHandle.
let wrapped = Remote {
future: AssertUnwindSafe(future).catch_unwind(),
tx: Some(tx),
Expand Down

0 comments on commit c8f3919

Please sign in to comment.