mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-07 00:00:08 +02:00
sync: don't inherit Send from parking_lot::*Guard (#4359)
This commit is contained in:
@@ -20,6 +20,7 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- test
|
- test
|
||||||
- test-unstable
|
- test-unstable
|
||||||
|
- test-parking_lot
|
||||||
- miri
|
- miri
|
||||||
- cross
|
- cross
|
||||||
- features
|
- features
|
||||||
@@ -77,6 +78,27 @@ jobs:
|
|||||||
# bench.yml workflow runs benchmarks only on linux.
|
# bench.yml workflow runs benchmarks only on linux.
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
|
||||||
|
test-parking_lot:
|
||||||
|
# The parking_lot crate has a feature called send_guard which changes when
|
||||||
|
# some of its types are Send. Tokio has some measures in place to prevent
|
||||||
|
# this from affecting when Tokio types are Send, and this test exists to
|
||||||
|
# ensure that those measures are working.
|
||||||
|
#
|
||||||
|
# This relies on the potentially affected Tokio type being listed in
|
||||||
|
# `tokio/tokio/tests/async_send_sync.rs`.
|
||||||
|
name: compile tests with parking lot send guards
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install Rust
|
||||||
|
run: rustup update stable
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
|
- name: Enable parking_lot send_guard feature
|
||||||
|
# Inserts the line "plsend = ["parking_lot/send_guard"]" right after [features]
|
||||||
|
run: sed -i '/\[features\]/a plsend = ["parking_lot/send_guard"]' tokio/Cargo.toml
|
||||||
|
- name: Compile tests with all features enabled
|
||||||
|
run: cargo build --workspace --all-features --tests
|
||||||
|
|
||||||
valgrind:
|
valgrind:
|
||||||
name: valgrind
|
name: valgrind
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -3,83 +3,143 @@
|
|||||||
//!
|
//!
|
||||||
//! This can be extended to additional types/methods as required.
|
//! This can be extended to additional types/methods as required.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::LockResult;
|
use std::sync::LockResult;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
// All types in this file are marked with PhantomData to ensure that
|
||||||
|
// parking_lot's send_guard feature does not leak through and affect when Tokio
|
||||||
|
// types are Send.
|
||||||
|
//
|
||||||
|
// See <https://github.com/tokio-rs/tokio/pull/4359> for more info.
|
||||||
|
|
||||||
// Types that do not need wrapping
|
// Types that do not need wrapping
|
||||||
pub(crate) use parking_lot::{MutexGuard, RwLockReadGuard, RwLockWriteGuard, WaitTimeoutResult};
|
pub(crate) use parking_lot::WaitTimeoutResult;
|
||||||
|
|
||||||
/// Adapter for `parking_lot::Mutex` to the `std::sync::Mutex` interface.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct Mutex<T: ?Sized>(parking_lot::Mutex<T>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct RwLock<T>(parking_lot::RwLock<T>);
|
pub(crate) struct Mutex<T: ?Sized>(PhantomData<std::sync::Mutex<T>>, parking_lot::Mutex<T>);
|
||||||
|
|
||||||
/// Adapter for `parking_lot::Condvar` to the `std::sync::Condvar` interface.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Condvar(parking_lot::Condvar);
|
pub(crate) struct RwLock<T>(PhantomData<std::sync::RwLock<T>>, parking_lot::RwLock<T>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct Condvar(PhantomData<std::sync::Condvar>, parking_lot::Condvar);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct MutexGuard<'a, T: ?Sized>(
|
||||||
|
PhantomData<std::sync::MutexGuard<'a, T>>,
|
||||||
|
parking_lot::MutexGuard<'a, T>,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct RwLockReadGuard<'a, T: ?Sized>(
|
||||||
|
PhantomData<std::sync::RwLockReadGuard<'a, T>>,
|
||||||
|
parking_lot::RwLockReadGuard<'a, T>,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct RwLockWriteGuard<'a, T: ?Sized>(
|
||||||
|
PhantomData<std::sync::RwLockWriteGuard<'a, T>>,
|
||||||
|
parking_lot::RwLockWriteGuard<'a, T>,
|
||||||
|
);
|
||||||
|
|
||||||
impl<T> Mutex<T> {
|
impl<T> Mutex<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new(t: T) -> Mutex<T> {
|
pub(crate) fn new(t: T) -> Mutex<T> {
|
||||||
Mutex(parking_lot::Mutex::new(t))
|
Mutex(PhantomData, parking_lot::Mutex::new(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(all(feature = "parking_lot", not(all(loom, test)),))]
|
#[cfg(all(feature = "parking_lot", not(all(loom, test)),))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "parking_lot",))))]
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "parking_lot",))))]
|
||||||
pub(crate) const fn const_new(t: T) -> Mutex<T> {
|
pub(crate) const fn const_new(t: T) -> Mutex<T> {
|
||||||
Mutex(parking_lot::const_mutex(t))
|
Mutex(PhantomData, parking_lot::const_mutex(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
|
pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
|
||||||
self.0.lock()
|
MutexGuard(PhantomData, self.1.lock())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
|
pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
|
||||||
self.0.try_lock()
|
self.1
|
||||||
|
.try_lock()
|
||||||
|
.map(|guard| MutexGuard(PhantomData, guard))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_mut(&mut self) -> &mut T {
|
pub(crate) fn get_mut(&mut self) -> &mut T {
|
||||||
self.0.get_mut()
|
self.1.get_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Additional methods `is_poisoned` and `into_inner`, can be
|
// Note: Additional methods `is_poisoned` and `into_inner`, can be
|
||||||
// provided here as needed.
|
// provided here as needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
self.1.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
self.1.deref_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> RwLock<T> {
|
impl<T> RwLock<T> {
|
||||||
pub(crate) fn new(t: T) -> RwLock<T> {
|
pub(crate) fn new(t: T) -> RwLock<T> {
|
||||||
RwLock(parking_lot::RwLock::new(t))
|
RwLock(PhantomData, parking_lot::RwLock::new(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
|
pub(crate) fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
|
||||||
Ok(self.0.read())
|
Ok(RwLockReadGuard(PhantomData, self.1.read()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
|
pub(crate) fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
|
||||||
Ok(self.0.write())
|
Ok(RwLockWriteGuard(PhantomData, self.1.write()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Deref for RwLockReadGuard<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
self.1.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Deref for RwLockWriteGuard<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
self.1.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> DerefMut for RwLockWriteGuard<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
self.1.deref_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Condvar {
|
impl Condvar {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new() -> Condvar {
|
pub(crate) fn new() -> Condvar {
|
||||||
Condvar(parking_lot::Condvar::new())
|
Condvar(PhantomData, parking_lot::Condvar::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn notify_one(&self) {
|
pub(crate) fn notify_one(&self) {
|
||||||
self.0.notify_one();
|
self.1.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn notify_all(&self) {
|
pub(crate) fn notify_all(&self) {
|
||||||
self.0.notify_all();
|
self.1.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -87,7 +147,7 @@ impl Condvar {
|
|||||||
&self,
|
&self,
|
||||||
mut guard: MutexGuard<'a, T>,
|
mut guard: MutexGuard<'a, T>,
|
||||||
) -> LockResult<MutexGuard<'a, T>> {
|
) -> LockResult<MutexGuard<'a, T>> {
|
||||||
self.0.wait(&mut guard);
|
self.1.wait(&mut guard.1);
|
||||||
Ok(guard)
|
Ok(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,10 +157,28 @@ impl Condvar {
|
|||||||
mut guard: MutexGuard<'a, T>,
|
mut guard: MutexGuard<'a, T>,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
|
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
|
||||||
let wtr = self.0.wait_for(&mut guard, timeout);
|
let wtr = self.1.wait_for(&mut guard.1, timeout);
|
||||||
Ok((guard, wtr))
|
Ok((guard, wtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Additional methods `wait_timeout_ms`, `wait_timeout_until`,
|
// Note: Additional methods `wait_timeout_ms`, `wait_timeout_until`,
|
||||||
// `wait_until` can be provided here as needed.
|
// `wait_until` can be provided here as needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.1, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'a, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.1, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'a, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.1, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user