Skip to content

Commit 6673596

Browse files
committed
try_upgrade
1 parent 5f3b84a commit 6673596

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

Diff for: library/std/src/sync/poison/rwlock.rs

+18
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,24 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
918918
None => Err(orig),
919919
}
920920
}
921+
922+
#[unstable(feature = "rwlock_try_upgrade", issue = "138559")]
923+
pub fn try_upgrade(orig: Self) -> Result<RwLockWriteGuard<'a, T>, RwLockReadGuard<'a, T>> {
924+
let rwl = &RwLock {
925+
data: UnsafeCell::new(orig.data.as_ptr().read()),
926+
poison: poison::Flag::new(),
927+
inner: *orig.inner_lock,
928+
};
929+
930+
// don't call the destructor
931+
forget(orig);
932+
933+
// SAFETY: We have ownership of the read guard, so it must be in read mode already
934+
match unsafe { rwl.inner.try_upgrade() } {
935+
true => Ok(RwLockWriteGuard::new(rwl).unwrap_or_else(PoisonError::into_inner)),
936+
false => Err(RwLockReadGuard::new(rwl).unwrap_or_else(PoisonError::into_inner)),
937+
}
938+
}
921939
}
922940

923941
impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {

Diff for: library/std/src/sys/sync/rwlock/futex.rs

+18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ fn is_write_locked(state: Primitive) -> bool {
3333
state & MASK == WRITE_LOCKED
3434
}
3535

36+
#[inline]
37+
fn is_read_locked(state: Primitive) -> bool {
38+
state & MASK == READ_LOCKED
39+
}
40+
3641
#[inline]
3742
fn has_readers_waiting(state: Primitive) -> bool {
3843
state & READERS_WAITING != 0
@@ -205,6 +210,19 @@ impl RwLock {
205210
}
206211
}
207212

213+
/// # Safety
214+
///
215+
/// The 'RwLock' must be read-locked in order to call this. Calling this function in a loop
216+
/// in at least 2 threads will deadlock.
217+
#[inline]
218+
pub unsafe fn try_upgrade(&self) -> bool {
219+
debg_assert!(
220+
is_read_locked(self.state),
221+
"RwLock must be read locked to call `try_upgrade`"
222+
);
223+
self.state.compare_exchange(READ_LOCKED, WRITE_LOCKED, Acquire, Relaxed).is_ok()
224+
}
225+
208226
#[cold]
209227
fn write_contended(&self) {
210228
let mut state = self.spin_write();

0 commit comments

Comments
 (0)