Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RwLockReadGuard covariant #45

Merged
merged 4 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,12 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> {
}

impl<T: ?Sized> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
// Remove the last bit and notify a waiting lock operation.
self.0.state.fetch_sub(1, Ordering::Release);
self.0.lock_ops.notify(1);
// SAFETY: we are droppig the mutex guard, therefore unlocking the mutex.
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
unsafe {
self.0.unlock_unchecked();
}
}
}

Expand Down Expand Up @@ -636,10 +638,12 @@ impl<T: ?Sized> MutexGuardArc<T> {
}

impl<T: ?Sized> Drop for MutexGuardArc<T> {
#[inline]
fn drop(&mut self) {
// Remove the last bit and notify a waiting lock operation.
self.0.state.fetch_sub(1, Ordering::Release);
self.0.lock_ops.notify(1);
// SAFETY: we are droppig the mutex guard, therefore unlocking the mutex.
unsafe {
self.0.unlock_unchecked();
}
}
}

Expand Down
35 changes: 30 additions & 5 deletions src/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use std::task::{Context, Poll};

mod raw;

use raw::*;

use self::raw::{RawRead, RawRwLock, RawUpgradableRead, RawUpgrade, RawWrite};
/// An async reader-writer lock.
///
/// This type of lock allows multiple readers or one writer at any point in time.
Expand Down Expand Up @@ -39,7 +38,8 @@ use raw::*;
/// # })
/// ```
pub struct RwLock<T: ?Sized> {
/// The locking implementation.
/// The underlying locking implementation.
/// Doesn't depend on `T`.
raw: RawRwLock,

/// The inner value.
Expand Down Expand Up @@ -317,8 +317,10 @@ impl<T: Default + ?Sized> Default for RwLock<T> {

/// The future returned by [`RwLock::read`].
pub struct Read<'a, T: ?Sized> {
/// Raw read lock acquisition future, doesn't depend on `T`.
raw: RawRead<'a>,

/// Pointer to the value protected by the lock. Covariant in `T`.
value: *const T,
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -349,7 +351,11 @@ impl<'a, T: ?Sized> Future for Read<'a, T> {

/// The future returned by [`RwLock::upgradable_read`].
pub struct UpgradableRead<'a, T: ?Sized> {
/// Raw upgradable read lock acquisition future, doesn't depend on `T`.
raw: RawUpgradableRead<'a>,

/// Pointer to the value protected by the lock. Invariant in `T`
/// as the upgradable lock could provide write access.
value: *mut T,
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -380,7 +386,10 @@ impl<'a, T: ?Sized> Future for UpgradableRead<'a, T> {

/// The future returned by [`RwLock::write`].
pub struct Write<'a, T: ?Sized> {
/// Raw write lock acquisition future, doesn't depend on `T`.
raw: RawWrite<'a>,

/// Pointer to the value protected by the lock. Invariant in `T`.
value: *mut T,
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -412,7 +421,11 @@ impl<'a, T: ?Sized> Future for Write<'a, T> {
/// A guard that releases the read lock when dropped.
#[clippy::has_significant_drop]
pub struct RwLockReadGuard<'a, T: ?Sized> {
/// Reference to underlying locking implementation.
/// Doesn't depend on `T`.
lock: &'a RawRwLock,

/// Pointer to the value protected by the lock. Covariant in `T`.
value: *const T,
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -452,8 +465,13 @@ impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
/// A guard that releases the upgradable read lock when dropped.
#[clippy::has_significant_drop]
pub struct RwLockUpgradableReadGuard<'a, T: ?Sized> {
// The guard holds a lock on the mutex!
/// Reference to underlying locking implementation.
/// Doesn't depend on `T`.
/// This guard holds a lock on the witer mutex!
lock: &'a RawRwLock,

/// Pointer to the value protected by the lock. Invariant in `T`
/// as the upgradable lock could provide write access.
value: *mut T,
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -598,7 +616,10 @@ impl<T: ?Sized> Deref for RwLockUpgradableReadGuard<'_, T> {

/// The future returned by [`RwLockUpgradableReadGuard::upgrade`].
pub struct Upgrade<'a, T: ?Sized> {
/// Raw read lock upgrade future, doesn't depend on `T`.
raw: RawUpgrade<'a>,

/// Pointer to the value protected by the lock. Invariant in `T`.
value: *mut T,
}

Expand Down Expand Up @@ -627,8 +648,12 @@ impl<'a, T: ?Sized> Future for Upgrade<'a, T> {
/// A guard that releases the write lock when dropped.
#[clippy::has_significant_drop]
pub struct RwLockWriteGuard<'a, T: ?Sized> {
// The guard holds a lock on the mutex!
/// Reference to underlying locking implementation.
/// Doesn't depend on `T`.
/// This guard holds a lock on the witer mutex!
lock: &'a RawRwLock,

/// Pointer to the value protected by the lock. Invariant in `T`.
value: *mut T,
}

Expand Down
10 changes: 9 additions & 1 deletion src/rwlock/raw.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//! Raw, unsafe reader-writer locking implementation,
//! doesn't depend on the data protected by the lock.
//! [`RwLock`](super::RwLock) is implemented in terms of this.
//!
//! Splitting the implementation this way allows instantiating
//! the locking code only once, and also lets us make
//! [`RwLockReadGuard`](super::RwLockReadGuard) covariant in `T`.

use std::future::Future;
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved
use std::mem::forget;
use std::pin::Pin;
Expand Down Expand Up @@ -76,7 +84,6 @@ impl RawRwLock {
}

#[inline]

pub(super) fn read(&self) -> RawRead<'_> {
RawRead {
lock: self,
Expand Down Expand Up @@ -403,6 +410,7 @@ enum WriteState<'a> {
/// The listener for the "no readers" event.
listener: Option<EventListener>,
},
Jules-Bertholet marked this conversation as resolved.
Show resolved Hide resolved

/// The future has completed.
Acquired,
}
Expand Down