Skip to content

Commit

Permalink
Merge pull request #243 from brain0/unlock_unsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu authored Jun 18, 2020
2 parents 1f6e68e + 1347de0 commit 99aa542
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 90 deletions.
2 changes: 1 addition & 1 deletion lock_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
//! .is_ok()
//! }
//!
//! fn unlock(&self) {
//! unsafe fn unlock(&self) {
//! self.0.store(false, Ordering::Release);
//! }
//! }
Expand Down
70 changes: 59 additions & 11 deletions lock_api/src/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,27 @@ pub unsafe trait RawMutex {
fn try_lock(&self) -> bool;

/// Unlocks this mutex.
fn unlock(&self);
///
/// # Safety
///
/// This method may only be called if the mutex is held in the current context, i.e. it must
/// be paired with a successful call to [`lock`], [`try_lock`], [`try_lock_for`] or [`try_lock_until`].
///
/// [`lock`]: #tymethod.lock
/// [`try_lock`]: #tymethod.try_lock
/// [`try_lock_for`]: trait.RawMutexTimed.html#tymethod.try_lock_for
/// [`try_lock_until`]: trait.RawMutexTimed.html#tymethod.try_lock_until
unsafe fn unlock(&self);

/// Checks whether the mutex is currently locked.
#[inline]
fn is_locked(&self) -> bool {
let acquired_lock = self.try_lock();
if acquired_lock {
self.unlock();
// Safety: The lock has been successfully acquired above.
unsafe {
self.unlock();
}
}
!acquired_lock
}
Expand All @@ -66,14 +79,28 @@ pub unsafe trait RawMutex {
/// unlocking, but may be necessary in certain circumstances.
pub unsafe trait RawMutexFair: RawMutex {
/// Unlocks this mutex using a fair unlock protocol.
fn unlock_fair(&self);
///
/// # Safety
///
/// This method may only be called if the mutex is held in the current context, see
/// the documentation of [`unlock`].
///
/// [`unlock`]: trait.RawMutex.html#tymethod.unlock
unsafe fn unlock_fair(&self);

/// Temporarily yields the mutex to a waiting thread if there is one.
///
/// This method is functionally equivalent to calling `unlock_fair` followed
/// by `lock`, however it can be much more efficient in the case where there
/// are no waiting threads.
fn bump(&self) {
///
/// # Safety
///
/// This method may only be called if the mutex is held in the current context, see
/// the documentation of [`unlock`].
///
/// [`unlock`]: trait.RawMutex.html#tymethod.unlock
unsafe fn bump(&self) {
self.unlock_fair();
self.lock();
}
Expand Down Expand Up @@ -436,7 +463,10 @@ impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> {
where
F: FnOnce() -> U,
{
s.mutex.raw.unlock();
// Safety: A MutexGuard always holds the lock.
unsafe {
s.mutex.raw.unlock();
}
defer!(s.mutex.raw.lock());
f()
}
Expand All @@ -457,7 +487,10 @@ impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> {
/// using this method instead of dropping the `MutexGuard` normally.
#[inline]
pub fn unlock_fair(s: Self) {
s.mutex.raw.unlock_fair();
// Safety: A MutexGuard always holds the lock.
unsafe {
s.mutex.raw.unlock_fair();
}
mem::forget(s);
}

Expand All @@ -472,7 +505,10 @@ impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> {
where
F: FnOnce() -> U,
{
s.mutex.raw.unlock_fair();
// Safety: A MutexGuard always holds the lock.
unsafe {
s.mutex.raw.unlock_fair();
}
defer!(s.mutex.raw.lock());
f()
}
Expand All @@ -484,7 +520,10 @@ impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> {
/// are no waiting threads.
#[inline]
pub fn bump(s: &mut Self) {
s.mutex.raw.bump();
// Safety: A MutexGuard always holds the lock.
unsafe {
s.mutex.raw.bump();
}
}
}

Expand All @@ -506,7 +545,10 @@ impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> DerefMut for MutexGuard<'a, R, T> {
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Drop for MutexGuard<'a, R, T> {
#[inline]
fn drop(&mut self) {
self.mutex.raw.unlock();
// Safety: A MutexGuard always holds the lock.
unsafe {
self.mutex.raw.unlock();
}
}
}

Expand Down Expand Up @@ -615,7 +657,10 @@ impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MappedMutexGuard<'a, R, T> {
/// using this method instead of dropping the `MutexGuard` normally.
#[inline]
pub fn unlock_fair(s: Self) {
s.raw.unlock_fair();
// Safety: A MutexGuard always holds the lock.
unsafe {
s.raw.unlock_fair();
}
mem::forget(s);
}
}
Expand All @@ -638,7 +683,10 @@ impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> DerefMut for MappedMutexGuard<'a, R,
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Drop for MappedMutexGuard<'a, R, T> {
#[inline]
fn drop(&mut self) {
self.raw.unlock();
// Safety: A MappedMutexGuard always holds the lock.
unsafe {
self.raw.unlock();
}
}
}

Expand Down
53 changes: 43 additions & 10 deletions lock_api/src/remutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ impl<R: RawMutex, G: GetThreadId> RawReentrantMutex<R, G> {

/// Unlocks this mutex. The inner mutex may not be unlocked if
/// this mutex was acquired previously in the current thread.
///
/// # Safety
///
/// This method may only be called if the mutex is held by the current thread.
#[inline]
pub fn unlock(&self) {
pub unsafe fn unlock(&self) {
let lock_count = self.lock_count.get() - 1;
self.lock_count.set(lock_count);
if lock_count == 0 {
Expand All @@ -137,8 +141,12 @@ impl<R: RawMutexFair, G: GetThreadId> RawReentrantMutex<R, G> {
/// Unlocks this mutex using a fair unlock protocol. The inner mutex
/// may not be unlocked if this mutex was acquired previously in the
/// current thread.
///
/// # Safety
///
/// This method may only be called if the mutex is held by the current thread.
#[inline]
pub fn unlock_fair(&self) {
pub unsafe fn unlock_fair(&self) {
let lock_count = self.lock_count.get() - 1;
self.lock_count.set(lock_count);
if lock_count == 0 {
Expand All @@ -152,8 +160,12 @@ impl<R: RawMutexFair, G: GetThreadId> RawReentrantMutex<R, G> {
/// This method is functionally equivalent to calling `unlock_fair` followed
/// by `lock`, however it can be much more efficient in the case where there
/// are no waiting threads.
///
/// # Safety
///
/// This method may only be called if the mutex is held by the current thread.
#[inline]
pub fn bump(&self) {
pub unsafe fn bump(&self) {
if self.lock_count.get() == 1 {
let id = self.owner.load(Ordering::Relaxed);
self.owner.store(0, Ordering::Relaxed);
Expand Down Expand Up @@ -554,7 +566,10 @@ impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> ReentrantMutexGu
where
F: FnOnce() -> U,
{
s.remutex.raw.unlock();
// Safety: A ReentrantMutexGuard always holds the lock.
unsafe {
s.remutex.raw.unlock();
}
defer!(s.remutex.raw.lock());
f()
}
Expand All @@ -577,7 +592,10 @@ impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
/// using this method instead of dropping the `ReentrantMutexGuard` normally.
#[inline]
pub fn unlock_fair(s: Self) {
s.remutex.raw.unlock_fair();
// Safety: A ReentrantMutexGuard always holds the lock
unsafe {
s.remutex.raw.unlock_fair();
}
mem::forget(s);
}

Expand All @@ -592,7 +610,10 @@ impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
where
F: FnOnce() -> U,
{
s.remutex.raw.unlock_fair();
// Safety: A ReentrantMutexGuard always holds the lock
unsafe {
s.remutex.raw.unlock_fair();
}
defer!(s.remutex.raw.lock());
f()
}
Expand All @@ -604,7 +625,10 @@ impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
/// are no waiting threads.
#[inline]
pub fn bump(s: &mut Self) {
s.remutex.raw.bump();
// Safety: A ReentrantMutexGuard always holds the lock
unsafe {
s.remutex.raw.bump();
}
}
}

Expand All @@ -623,7 +647,10 @@ impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Drop
{
#[inline]
fn drop(&mut self) {
self.remutex.raw.unlock();
// Safety: A ReentrantMutexGuard always holds the lock.
unsafe {
self.remutex.raw.unlock();
}
}
}

Expand Down Expand Up @@ -742,7 +769,10 @@ impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
/// using this method instead of dropping the `ReentrantMutexGuard` normally.
#[inline]
pub fn unlock_fair(s: Self) {
s.raw.unlock_fair();
// Safety: A MappedReentrantMutexGuard always holds the lock
unsafe {
s.raw.unlock_fair();
}
mem::forget(s);
}
}
Expand All @@ -762,7 +792,10 @@ impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Drop
{
#[inline]
fn drop(&mut self) {
self.raw.unlock();
// Safety: A MappedReentrantMutexGuard always holds the lock.
unsafe {
self.raw.unlock();
}
}
}

Expand Down
Loading

0 comments on commit 99aa542

Please sign in to comment.