From aef2d64b0a519ff6726f8c139ee1d3e6b1959b0b Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 16 Jul 2021 09:50:03 +0200 Subject: [PATCH] task: remove mutex in JoinError (#3959) --- tokio/src/runtime/task/error.rs | 9 +++++---- tokio/src/util/mod.rs | 3 +++ tokio/src/util/sync_wrapper.rs | 26 ++++++++++++++++++++++++++ tokio/tests/async_send_sync.rs | 1 + 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 tokio/src/util/sync_wrapper.rs diff --git a/tokio/src/runtime/task/error.rs b/tokio/src/runtime/task/error.rs index 177fe65e9b9..17fb09390ae 100644 --- a/tokio/src/runtime/task/error.rs +++ b/tokio/src/runtime/task/error.rs @@ -1,7 +1,8 @@ use std::any::Any; use std::fmt; use std::io; -use std::sync::Mutex; + +use crate::util::SyncWrapper; cfg_rt! { /// Task failed to execute to completion. @@ -12,7 +13,7 @@ cfg_rt! { enum Repr { Cancelled, - Panic(Mutex>), + Panic(SyncWrapper>), } impl JoinError { @@ -24,7 +25,7 @@ impl JoinError { pub(crate) fn panic(err: Box) -> JoinError { JoinError { - repr: Repr::Panic(Mutex::new(err)), + repr: Repr::Panic(SyncWrapper::new(err)), } } @@ -106,7 +107,7 @@ impl JoinError { /// ``` pub fn try_into_panic(self) -> Result, JoinError> { match self.repr { - Repr::Panic(p) => Ok(p.into_inner().expect("Extracting panic from mutex")), + Repr::Panic(p) => Ok(p.into_inner()), _ => Err(self), } } diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index b267125b15b..bcc73ed68de 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -21,6 +21,9 @@ cfg_rt! { mod wake; pub(crate) use wake::WakerRef; pub(crate) use wake::{waker_ref, Wake}; + + mod sync_wrapper; + pub(crate) use sync_wrapper::SyncWrapper; } cfg_rt_multi_thread! { diff --git a/tokio/src/util/sync_wrapper.rs b/tokio/src/util/sync_wrapper.rs new file mode 100644 index 00000000000..5ffc8f96b16 --- /dev/null +++ b/tokio/src/util/sync_wrapper.rs @@ -0,0 +1,26 @@ +//! This module contains a type that can make `Send + !Sync` types `Sync` by +//! disallowing all immutable access to the value. +//! +//! A similar primitive is provided in the `sync_wrapper` crate. + +pub(crate) struct SyncWrapper { + value: T, +} + +// safety: The SyncWrapper being send allows you to send the inner value across +// thread boundaries. +unsafe impl Send for SyncWrapper {} + +// safety: An immutable reference to a SyncWrapper is useless, so moving such an +// immutable reference across threads is safe. +unsafe impl Sync for SyncWrapper {} + +impl SyncWrapper { + pub(crate) fn new(value: T) -> Self { + Self { value } + } + + pub(crate) fn into_inner(self) -> T { + self.value + } +} diff --git a/tokio/tests/async_send_sync.rs b/tokio/tests/async_send_sync.rs index 12d13239387..97118ce66dc 100644 --- a/tokio/tests/async_send_sync.rs +++ b/tokio/tests/async_send_sync.rs @@ -452,6 +452,7 @@ assert_value!(tokio::task::LocalSet: !Send & !Sync & Unpin); assert_value!(tokio::task::JoinHandle: Send & Sync & Unpin); assert_value!(tokio::task::JoinHandle: Send & Sync & Unpin); assert_value!(tokio::task::JoinHandle: !Send & !Sync & Unpin); +assert_value!(tokio::task::JoinError: Send & Sync & Unpin); assert_value!(tokio::runtime::Builder: Send & Sync & Unpin); assert_value!(tokio::runtime::EnterGuard<'_>: Send & Sync & Unpin);