-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
Added unlock functionality to mutex guard and rw lock guards #149189
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
base: main
Are you sure you want to change the base?
Changes from all commits
0f76c01
53533d8
b782dc6
9ce5968
a1aa681
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 |
|---|---|---|
|
|
@@ -98,6 +98,9 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} | |
| #[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutexGuard")] | ||
| pub struct MutexGuard<'a, T: ?Sized + 'a> { | ||
| lock: &'a Mutex<T>, | ||
| /// The unlocked state is used to prevent double unlocking of guards upon panicking in | ||
| /// unlocked scopes. | ||
| unlocked: bool, | ||
| } | ||
|
|
||
| /// A [`MutexGuard`] is not `Send` to maximize platform portability. | ||
|
|
@@ -447,7 +450,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { | |
|
|
||
| impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { | ||
| unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> { | ||
| return MutexGuard { lock }; | ||
| MutexGuard { lock, unlocked: false } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -471,8 +474,10 @@ impl<T: ?Sized> DerefMut for MutexGuard<'_, T> { | |
| impl<T: ?Sized> Drop for MutexGuard<'_, T> { | ||
| #[inline] | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| self.lock.inner.unlock(); | ||
| if !self.unlocked { | ||
| unsafe { | ||
| self.lock.inner.unlock(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -496,6 +501,48 @@ pub(super) fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::M | |
| &guard.lock.inner | ||
| } | ||
|
|
||
| impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { | ||
| /// Unlocks the [`MutexGuard`] for the scope of `func` and acquires it again after. | ||
| /// Panics won't lock the guard again. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ``` | ||
| /// #[feature(unlockable_guards)] | ||
| /// | ||
| /// use std::sync::nonpoison::Mutex; | ||
| /// use std::sync::nonpoison::MutexGuard; | ||
| /// use std::sync::nonpoison::TryLockResult; | ||
| /// | ||
| /// let mutex = Mutex::new(1usize); | ||
| /// let mut guard = mutex.lock(); | ||
| /// | ||
| /// // guard is locked and can be used here | ||
| /// *guard = 5; | ||
| /// | ||
| /// MutexGuard::unlocked(&mut guard, || { | ||
| /// // guard is locked and can be acquired potentially from another thread | ||
| /// assert!(matches!(mutex.try_lock(), TryLockResult::Ok(_))); | ||
| /// }); | ||
| /// | ||
| /// // guard is locked again | ||
| /// assert_eq!(*guard, 5); | ||
| /// ``` | ||
| #[unstable(feature = "unlockable_guards", issue = "148568")] | ||
| pub fn unlocked<F>(self: &mut Self, func: F) -> () | ||
| where | ||
| F: FnOnce() -> (), | ||
| { | ||
| self.unlocked = true; | ||
| unsafe { self.lock.inner.unlock() }; | ||
|
|
||
| func(); | ||
|
|
||
| self.lock.inner.lock(); | ||
|
Comment on lines
+537
to
+541
Member
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. Not a fundamental design issue, but the implementation looks unsound in the presence of panics since it leaves the Mutex unlocked when exiting the function let mutex = Mutex::new(1);
let mut guard = mutex.lock().unwrap();
panic::catch_unwind(AssertUnwindSafe(|| MutexGuard::unlocked(&mut guard, || panic!())));
let ref1 = &mut *guard;
let ref2 = &mut *mutex.lock();
dbg!(ref1, ref2);lock_api doesn't have this issue since it calls lock() in a local's edit: Ah, I overlooked the new
Member
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. Oh yes, that's unsound. I don't think the "no relock during panic" guarantee can be soundly provided, at least if |
||
| self.unlocked = false; | ||
| } | ||
| } | ||
|
|
||
| impl<'a, T: ?Sized> MutexGuard<'a, T> { | ||
| /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g. | ||
| /// an enum variant. | ||
|
|
||
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.
How important is this guarantee? I find it unfortunate that this necessitates adding a field and an additional check in the
Dropimplementation, which affects all code usingMutexGuards, not just code that callsunlocked.