Skip to content

Commit 8d64a4a

Browse files
authored
Merge pull request #386 from Jules-Bertholet/with-upgraded
2 parents aa2e65d + 7f83d8d commit 8d64a4a

1 file changed

Lines changed: 241 additions & 8 deletions

File tree

lock_api/src/rwlock.rs

Lines changed: 241 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,7 +1897,7 @@ impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a,
18971897
f()
18981898
}
18991899

1900-
/// Atomically upgrades an upgradable read lock lock into a exclusive write lock,
1900+
/// Atomically upgrades an upgradable read lock lock into an exclusive write lock,
19011901
/// blocking the current thread until it can be acquired.
19021902
pub fn upgrade(s: Self) -> RwLockWriteGuard<'a, R, T> {
19031903
// Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
@@ -1912,7 +1912,7 @@ impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a,
19121912
}
19131913
}
19141914

1915-
/// Tries to atomically upgrade an upgradable read lock into a exclusive write lock.
1915+
/// Tries to atomically upgrade an upgradable read lock into an exclusive write lock.
19161916
///
19171917
/// If the access could not be granted at this time, then the current guard is returned.
19181918
pub fn try_upgrade(s: Self) -> Result<RwLockWriteGuard<'a, R, T>, Self> {
@@ -2005,10 +2005,60 @@ impl<'a, R: RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> RwLockUpgradableRead
20052005
marker: PhantomData,
20062006
}
20072007
}
2008+
2009+
/// First, atomically upgrades an upgradable read lock lock into an exclusive write lock,
2010+
/// blocking the current thread until it can be acquired.
2011+
///
2012+
/// Then, calls the provided closure with an exclusive reference to the lock's data.
2013+
///
2014+
/// Finally, atomically downgrades the lock back to an upgradable read lock.
2015+
/// The closure's return value is wrapped in `Some` and returned.
2016+
///
2017+
/// This function only requires a mutable reference to the guard, unlike
2018+
/// `upgrade` which takes the guard by value.
2019+
pub fn with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Ret {
2020+
unsafe {
2021+
self.rwlock.raw.upgrade();
2022+
}
2023+
2024+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2025+
// This will restore the state the lock was in at the start of the function.
2026+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2027+
2028+
// Safety: We upgraded the lock, so we have mutable access to the data.
2029+
// When this function returns, whether by drop or panic,
2030+
// the drop guard will downgrade it back to an upgradeable lock.
2031+
f(unsafe { &mut *self.rwlock.data.get() })
2032+
}
2033+
2034+
/// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock.
2035+
///
2036+
/// If the access could not be granted at this time, then `None` is returned.
2037+
///
2038+
/// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
2039+
/// and finally downgrades the lock back to an upgradable read lock.
2040+
/// The closure's return value is wrapped in `Some` and returned.
2041+
///
2042+
/// This function only requires a mutable reference to the guard, unlike
2043+
/// `try_upgrade` which takes the guard by value.
2044+
pub fn try_with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Option<Ret> {
2045+
if unsafe { self.rwlock.raw.try_upgrade() } {
2046+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2047+
// This will restore the state the lock was in at the start of the function.
2048+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2049+
2050+
// Safety: We upgraded the lock, so we have mutable access to the data.
2051+
// When this function returns, whether by drop or panic,
2052+
// the drop guard will downgrade it back to an upgradeable lock.
2053+
Some(f(unsafe { &mut *self.rwlock.data.get() }))
2054+
} else {
2055+
None
2056+
}
2057+
}
20082058
}
20092059

20102060
impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> {
2011-
/// Tries to atomically upgrade an upgradable read lock into a exclusive
2061+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
20122062
/// write lock, until a timeout is reached.
20132063
///
20142064
/// If the access could not be granted before the timeout expires, then
@@ -2030,7 +2080,7 @@ impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuar
20302080
}
20312081
}
20322082

2033-
/// Tries to atomically upgrade an upgradable read lock into a exclusive
2083+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
20342084
/// write lock, until a timeout is reached.
20352085
///
20362086
/// If the access could not be granted before the timeout expires, then
@@ -2054,6 +2104,72 @@ impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuar
20542104
}
20552105
}
20562106

2107+
impl<'a, R: RawRwLockUpgradeTimed + RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a>
2108+
RwLockUpgradableReadGuard<'a, R, T>
2109+
{
2110+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
2111+
/// write lock, until a timeout is reached.
2112+
///
2113+
/// If the access could not be granted before the timeout expires, then
2114+
/// `None` is returned.
2115+
///
2116+
/// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
2117+
/// and finally downgrades the lock back to an upgradable read lock.
2118+
/// The closure's return value is wrapped in `Some` and returned.
2119+
///
2120+
/// This function only requires a mutable reference to the guard, unlike
2121+
/// `try_upgrade_for` which takes the guard by value.
2122+
pub fn try_with_upgraded_for<Ret, F: FnOnce(&mut T) -> Ret>(
2123+
&mut self,
2124+
timeout: R::Duration,
2125+
f: F,
2126+
) -> Option<Ret> {
2127+
if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } {
2128+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2129+
// This will restore the state the lock was in at the start of the function.
2130+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2131+
2132+
// Safety: We upgraded the lock, so we have mutable access to the data.
2133+
// When this function returns, whether by drop or panic,
2134+
// the drop guard will downgrade it back to an upgradeable lock.
2135+
Some(f(unsafe { &mut *self.rwlock.data.get() }))
2136+
} else {
2137+
None
2138+
}
2139+
}
2140+
2141+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
2142+
/// write lock, until a timeout is reached.
2143+
///
2144+
/// If the access could not be granted before the timeout expires, then
2145+
/// `None` is returned.
2146+
///
2147+
/// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
2148+
/// and finally downgrades the lock back to an upgradable read lock.
2149+
/// The closure's return value is wrapped in `Some` and returned.
2150+
///
2151+
/// This function only requires a mutable reference to the guard, unlike
2152+
/// `try_upgrade_until` which takes the guard by value.
2153+
pub fn try_with_upgraded_until<Ret, F: FnOnce(&mut T) -> Ret>(
2154+
&mut self,
2155+
timeout: R::Instant,
2156+
f: F,
2157+
) -> Option<Ret> {
2158+
if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } {
2159+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2160+
// This will restore the state the lock was in at the start of the function.
2161+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2162+
2163+
// Safety: We upgraded the lock, so we have mutable access to the data.
2164+
// When this function returns, whether by drop or panic,
2165+
// the drop guard will downgrade it back to an upgradeable lock.
2166+
Some(f(unsafe { &mut *self.rwlock.data.get() }))
2167+
} else {
2168+
None
2169+
}
2170+
}
2171+
}
2172+
20572173
impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> Deref for RwLockUpgradableReadGuard<'a, R, T> {
20582174
type Target = T;
20592175
#[inline]
@@ -2129,7 +2245,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
21292245
f()
21302246
}
21312247

2132-
/// Atomically upgrades an upgradable read lock lock into a exclusive write lock,
2248+
/// Atomically upgrades an upgradable read lock lock into an exclusive write lock,
21332249
/// blocking the current thread until it can be acquired.
21342250
pub fn upgrade(s: Self) -> ArcRwLockWriteGuard<R, T> {
21352251
// Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
@@ -2148,7 +2264,7 @@ impl<R: RawRwLockUpgrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
21482264
}
21492265
}
21502266

2151-
/// Tries to atomically upgrade an upgradable read lock into a exclusive write lock.
2267+
/// Tries to atomically upgrade an upgradable read lock into an exclusive write lock.
21522268
///
21532269
/// If the access could not be granted at this time, then the current guard is returned.
21542270
pub fn try_upgrade(s: Self) -> Result<ArcRwLockWriteGuard<R, T>, Self> {
@@ -2237,11 +2353,61 @@ impl<R: RawRwLockUpgradeDowngrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T>
22372353
marker: PhantomData,
22382354
}
22392355
}
2356+
2357+
/// First, atomically upgrades an upgradable read lock lock into an exclusive write lock,
2358+
/// blocking the current thread until it can be acquired.
2359+
///
2360+
/// Then, calls the provided closure with an exclusive reference to the lock's data.
2361+
///
2362+
/// Finally, atomically downgrades the lock back to an upgradable read lock.
2363+
/// The closure's return value is returned.
2364+
///
2365+
/// This function only requires a mutable reference to the guard, unlike
2366+
/// `upgrade` which takes the guard by value.
2367+
pub fn with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Ret {
2368+
unsafe {
2369+
self.rwlock.raw.upgrade();
2370+
}
2371+
2372+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2373+
// This will restore the state the lock was in at the start of the function.
2374+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2375+
2376+
// Safety: We upgraded the lock, so we have mutable access to the data.
2377+
// When this function returns, whether by drop or panic,
2378+
// the drop guard will downgrade it back to an upgradeable lock.
2379+
f(unsafe { &mut *self.rwlock.data.get() })
2380+
}
2381+
2382+
/// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock.
2383+
///
2384+
/// If the access could not be granted at this time, then `None` is returned.
2385+
///
2386+
/// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
2387+
/// and finally downgrades the lock back to an upgradable read lock.
2388+
/// The closure's return value is wrapped in `Some` and returned.
2389+
///
2390+
/// This function only requires a mutable reference to the guard, unlike
2391+
/// `try_upgrade` which takes the guard by value.
2392+
pub fn try_with_upgraded<Ret, F: FnOnce(&mut T) -> Ret>(&mut self, f: F) -> Option<Ret> {
2393+
if unsafe { self.rwlock.raw.try_upgrade() } {
2394+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2395+
// This will restore the state the lock was in at the start of the function.
2396+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2397+
2398+
// Safety: We upgraded the lock, so we have mutable access to the data.
2399+
// When this function returns, whether by drop or panic,
2400+
// the drop guard will downgrade it back to an upgradeable lock.
2401+
Some(f(unsafe { &mut *self.rwlock.data.get() }))
2402+
} else {
2403+
None
2404+
}
2405+
}
22402406
}
22412407

22422408
#[cfg(feature = "arc_lock")]
22432409
impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
2244-
/// Tries to atomically upgrade an upgradable read lock into a exclusive
2410+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
22452411
/// write lock, until a timeout is reached.
22462412
///
22472413
/// If the access could not be granted before the timeout expires, then
@@ -2265,7 +2431,7 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
22652431
}
22662432
}
22672433

2268-
/// Tries to atomically upgrade an upgradable read lock into a exclusive
2434+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
22692435
/// write lock, until a timeout is reached.
22702436
///
22712437
/// If the access could not be granted before the timeout expires, then
@@ -2291,6 +2457,73 @@ impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> {
22912457
}
22922458
}
22932459

2460+
#[cfg(feature = "arc_lock")]
2461+
impl<R: RawRwLockUpgradeTimed + RawRwLockUpgradeDowngrade, T: ?Sized>
2462+
ArcRwLockUpgradableReadGuard<R, T>
2463+
{
2464+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
2465+
/// write lock, until a timeout is reached.
2466+
///
2467+
/// If the access could not be granted before the timeout expires, then
2468+
/// `None` is returned.
2469+
///
2470+
/// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
2471+
/// and finally downgrades the lock back to an upgradable read lock.
2472+
/// The closure's return value is wrapped in `Some` and returned.
2473+
///
2474+
/// This function only requires a mutable reference to the guard, unlike
2475+
/// `try_upgrade_for` which takes the guard by value.
2476+
pub fn try_with_upgraded_for<Ret, F: FnOnce(&mut T) -> Ret>(
2477+
&mut self,
2478+
timeout: R::Duration,
2479+
f: F,
2480+
) -> Option<Ret> {
2481+
if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } {
2482+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2483+
// This will restore the state the lock was in at the start of the function.
2484+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2485+
2486+
// Safety: We upgraded the lock, so we have mutable access to the data.
2487+
// When this function returns, whether by drop or panic,
2488+
// the drop guard will downgrade it back to an upgradeable lock.
2489+
Some(f(unsafe { &mut *self.rwlock.data.get() }))
2490+
} else {
2491+
None
2492+
}
2493+
}
2494+
2495+
/// Tries to atomically upgrade an upgradable read lock into an exclusive
2496+
/// write lock, until a timeout is reached.
2497+
///
2498+
/// If the access could not be granted before the timeout expires, then
2499+
/// `None` is returned.
2500+
///
2501+
/// Otherwise, calls the provided closure with an exclusive reference to the lock's data,
2502+
/// and finally downgrades the lock back to an upgradable read lock.
2503+
/// The closure's return value is wrapped in `Some` and returned.
2504+
///
2505+
/// This function only requires a mutable reference to the guard, unlike
2506+
/// `try_upgrade_until` which takes the guard by value.
2507+
pub fn try_with_upgraded_until<Ret, F: FnOnce(&mut T) -> Ret>(
2508+
&mut self,
2509+
timeout: R::Instant,
2510+
f: F,
2511+
) -> Option<Ret> {
2512+
if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } {
2513+
// Safety: We just upgraded the lock, so we have mutable access to the data.
2514+
// This will restore the state the lock was in at the start of the function.
2515+
defer!(unsafe { self.rwlock.raw.downgrade_upgradable() });
2516+
2517+
// Safety: We upgraded the lock, so we have mutable access to the data.
2518+
// When this function returns, whether by drop or panic,
2519+
// the drop guard will downgrade it back to an upgradeable lock.
2520+
Some(f(unsafe { &mut *self.rwlock.data.get() }))
2521+
} else {
2522+
None
2523+
}
2524+
}
2525+
}
2526+
22942527
#[cfg(feature = "arc_lock")]
22952528
impl<R: RawRwLockUpgrade, T: ?Sized> Deref for ArcRwLockUpgradableReadGuard<R, T> {
22962529
type Target = T;

0 commit comments

Comments
 (0)