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
Add arc_lock feature, with guards that can be accessed from inside of Arc #291
Changes from 1 commit
850a2e5
a12a47f
c95dd20
2a2ebfa
e687378
8b0eb2f
a9f5671
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,9 @@ use core::marker::PhantomData; | |
use core::mem; | ||
use core::ops::{Deref, DerefMut}; | ||
|
||
#[cfg(feature = "arc_lock")] | ||
use alloc::sync::Arc; | ||
|
||
#[cfg(feature = "owning_ref")] | ||
use owning_ref::StableAddress; | ||
|
||
|
@@ -286,6 +289,45 @@ impl<R: RawMutex, T: ?Sized> Mutex<R, T> { | |
pub fn data_ptr(&self) -> *mut T { | ||
self.data.get() | ||
} | ||
|
||
/// # Safety | ||
/// | ||
/// The lock needs to be held for the behavior of this function to be defined. | ||
#[cfg(feature = "arc_lock")] | ||
#[inline] | ||
unsafe fn guard_arc(this: &Arc<Self>) -> ArcMutexGuard<R, T> { | ||
ArcMutexGuard { | ||
mutex: this.clone(), | ||
marker: PhantomData, | ||
} | ||
} | ||
|
||
/// Acquires a lock through an `Arc`. | ||
/// | ||
/// This method is similar to the `lock` method; however, it requires the `Mutex` to be inside of an `Arc` | ||
/// and the resulting mutex guard has no lifetime requirements. | ||
#[cfg(feature = "arc_lock")] | ||
#[inline] | ||
pub fn lock_arc(this: &Arc<Self>) -> ArcMutexGuard<R, T> { | ||
this.raw.lock(); | ||
// SAFETY: the locking guarantee is upheld | ||
unsafe { Self::guard_arc(this) } | ||
} | ||
|
||
/// Attempts to acquire a lock through an `Arc`. | ||
/// | ||
/// This method is similar to the `try_lock` method; however, it requires the `Mutex` to be inside of an | ||
/// `Arc` and the resulting mutex guard has no lifetime requirements. | ||
#[cfg(feature = "arc_lock")] | ||
#[inline] | ||
pub fn try_lock_arc(this: &Arc<Self>) -> Option<ArcMutexGuard<R, T>> { | ||
if this.raw.try_lock() { | ||
// SAFETY: locking guarantee is upheld | ||
Some(unsafe { Self::guard_arc(this) }) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<R: RawMutexFair, T: ?Sized> Mutex<R, T> { | ||
|
@@ -336,6 +378,39 @@ impl<R: RawMutexTimed, T: ?Sized> Mutex<R, T> { | |
None | ||
} | ||
} | ||
|
||
/// Attempts to acquire this lock through an `Arc` until a timeout is reached. | ||
/// | ||
/// This method is similar to the `try_lock_for` method; however, it requires the `Mutex` to be inside of an | ||
/// `Arc` and the resulting mutex guard has no lifetime requirements. | ||
#[cfg(feature = "arc_lock")] | ||
#[inline] | ||
pub fn try_lock_for_arc(this: &Arc<Self>, timeout: R::Duration) -> Option<ArcMutexGuard<R, T>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if this.raw.try_lock_for(timeout) { | ||
// SAFETY: locking guarantee is upheld | ||
Some(unsafe { Self::guard_arc(this) }) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
/// Attempts to acquire this lock through an `Arc` until a timeout is reached. | ||
/// | ||
/// This method is similar to the `try_lock_until` method; however, it requires the `Mutex` to be inside of | ||
/// an `Arc` and the resulting mutex guard has no lifetime requirements. | ||
#[cfg(feature = "arc_lock")] | ||
#[inline] | ||
pub fn try_lock_until_arc( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
this: &Arc<Self>, | ||
timeout: R::Instant, | ||
) -> Option<ArcMutexGuard<R, T>> { | ||
if this.raw.try_lock_until(timeout) { | ||
// SAFETY: locking guarantee is upheld | ||
Some(unsafe { Self::guard_arc(this) }) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<R: RawMutex, T: ?Sized + Default> Default for Mutex<R, T> { | ||
|
@@ -583,6 +658,112 @@ impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display for Mutex | |
#[cfg(feature = "owning_ref")] | ||
unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'a, R, T> {} | ||
|
||
/// An RAII mutex guard returned by the `Arc` locking operations on `Mutex`. This is similar to the `MutexGuard` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Split the first sentence into a separate paragraph. This summary is shown in the module documentation index. |
||
/// struct, except instead of using a reference to unlock the `Mutex` it uses an `Arc<Mutex>`. This has several | ||
/// advantages, most notably that it has an `'static` lifetime. | ||
#[cfg(feature = "arc_lock")] | ||
#[must_use = "if unused the Mutex will immediately unlock"] | ||
pub struct ArcMutexGuard<R: RawMutex, T: ?Sized> { | ||
mutex: Arc<Mutex<R, T>>, | ||
marker: PhantomData<R::GuardMarker>, | ||
} | ||
|
||
#[cfg(feature = "arc_lock")] | ||
impl<R: RawMutex, T: ?Sized> ArcMutexGuard<R, T> { | ||
/// Returns a reference to the `Mutex` this is guarding, contained in its `Arc`. | ||
#[inline] | ||
pub fn mutex(&self) -> &Arc<Mutex<R, T>> { | ||
&self.mutex | ||
} | ||
|
||
/// Temporarily unlocks the mutex to execute the given function. | ||
/// | ||
/// This is safe because `&mut` guarantees that there exist no other | ||
/// references to the data protected by the mutex. | ||
#[inline] | ||
pub fn unlocked<F, U>(s: &mut Self, f: F) -> U | ||
where | ||
F: FnOnce() -> U, | ||
{ | ||
// Safety: A MutexGuard always holds the lock. | ||
unsafe { | ||
s.mutex.raw.unlock(); | ||
} | ||
defer!(s.mutex.raw.lock()); | ||
f() | ||
} | ||
} | ||
|
||
#[cfg(feature = "arc_lock")] | ||
impl<R: RawMutexFair, T: ?Sized> ArcMutexGuard<R, T> { | ||
/// Unlocks the mutex using a fair unlock protocol. | ||
/// | ||
/// This is functionally identical to the `unlock_fair` method on [`MutexGuard`]. | ||
#[inline] | ||
pub fn unlock_fair(s: Self) { | ||
// Safety: A MutexGuard always holds the lock. | ||
unsafe { | ||
s.mutex.raw.unlock_fair(); | ||
} | ||
mem::forget(s); | ||
} | ||
|
||
/// Temporarily unlocks the mutex to execute the given function. | ||
/// | ||
/// This is functionally identical to the `unlocked_fair` method on [`MutexGuard`]. | ||
#[inline] | ||
pub fn unlocked_fair<F, U>(s: &mut Self, f: F) -> U | ||
where | ||
F: FnOnce() -> U, | ||
{ | ||
// Safety: A MutexGuard always holds the lock. | ||
unsafe { | ||
s.mutex.raw.unlock_fair(); | ||
} | ||
defer!(s.mutex.raw.lock()); | ||
f() | ||
} | ||
|
||
/// Temporarily yields the mutex to a waiting thread if there is one. | ||
/// | ||
/// This is functionally identical to the `bump` method on [`MutexGuard`]. | ||
#[inline] | ||
pub fn bump(s: &mut Self) { | ||
// Safety: A MutexGuard always holds the lock. | ||
unsafe { | ||
s.mutex.raw.bump(); | ||
} | ||
} | ||
} | ||
|
||
#[cfg(feature = "arc_lock")] | ||
impl<R: RawMutex, T: ?Sized> Deref for ArcMutexGuard<R, T> { | ||
type Target = T; | ||
#[inline] | ||
fn deref(&self) -> &T { | ||
unsafe { &*self.mutex.data.get() } | ||
} | ||
} | ||
|
||
#[cfg(feature = "arc_lock")] | ||
impl<R: RawMutex, T: ?Sized> DerefMut for ArcMutexGuard<R, T> { | ||
#[inline] | ||
fn deref_mut(&mut self) -> &mut T { | ||
unsafe { &mut *self.mutex.data.get() } | ||
} | ||
} | ||
|
||
#[cfg(feature = "arc_lock")] | ||
impl<R: RawMutex, T: ?Sized> Drop for ArcMutexGuard<R, T> { | ||
#[inline] | ||
fn drop(&mut self) { | ||
// Safety: A MutexGuard always holds the lock. | ||
unsafe { | ||
self.mutex.raw.unlock(); | ||
} | ||
} | ||
} | ||
|
||
/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a | ||
/// subfield of the protected data. | ||
/// | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use
self
here which allowslock_arc
to be called with dot syntax.