Skip to content

Commit 463b128

Browse files
EFanZhgitbot
authored and
gitbot
committed
Add value accessor methods to Mutex and RwLock
1 parent e069317 commit 463b128

File tree

5 files changed

+517
-86
lines changed

5 files changed

+517
-86
lines changed

std/src/sync/mutex.rs

+104-6
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ mod tests;
44
use crate::cell::UnsafeCell;
55
use crate::fmt;
66
use crate::marker::PhantomData;
7-
use crate::mem::ManuallyDrop;
7+
use crate::mem::{self, ManuallyDrop};
88
use crate::ops::{Deref, DerefMut};
99
use crate::ptr::NonNull;
10-
use crate::sync::{LockResult, TryLockError, TryLockResult, poison};
10+
use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
1111
use crate::sys::sync as sys;
1212

1313
/// A mutual exclusion primitive useful for protecting shared data
@@ -273,6 +273,100 @@ impl<T> Mutex<T> {
273273
pub const fn new(t: T) -> Mutex<T> {
274274
Mutex { inner: sys::Mutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
275275
}
276+
277+
/// Returns the contained value by cloning it.
278+
///
279+
/// # Errors
280+
///
281+
/// If another user of this mutex panicked while holding the mutex, then
282+
/// this call will return an error instead.
283+
///
284+
/// # Examples
285+
///
286+
/// ```
287+
/// #![feature(lock_value_accessors)]
288+
///
289+
/// use std::sync::Mutex;
290+
///
291+
/// let mut mutex = Mutex::new(7);
292+
///
293+
/// assert_eq!(mutex.get_cloned().unwrap(), 7);
294+
/// ```
295+
#[unstable(feature = "lock_value_accessors", issue = "133407")]
296+
pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
297+
where
298+
T: Clone,
299+
{
300+
match self.lock() {
301+
Ok(guard) => Ok((*guard).clone()),
302+
Err(_) => Err(PoisonError::new(())),
303+
}
304+
}
305+
306+
/// Sets the contained value.
307+
///
308+
/// # Errors
309+
///
310+
/// If another user of this mutex panicked while holding the mutex, then
311+
/// this call will return an error containing the provided `value` instead.
312+
///
313+
/// # Examples
314+
///
315+
/// ```
316+
/// #![feature(lock_value_accessors)]
317+
///
318+
/// use std::sync::Mutex;
319+
///
320+
/// let mut mutex = Mutex::new(7);
321+
///
322+
/// assert_eq!(mutex.get_cloned().unwrap(), 7);
323+
/// mutex.set(11).unwrap();
324+
/// assert_eq!(mutex.get_cloned().unwrap(), 11);
325+
/// ```
326+
#[unstable(feature = "lock_value_accessors", issue = "133407")]
327+
pub fn set(&self, value: T) -> Result<(), PoisonError<T>> {
328+
if mem::needs_drop::<T>() {
329+
// If the contained value has non-trivial destructor, we
330+
// call that destructor after the lock being released.
331+
self.replace(value).map(drop)
332+
} else {
333+
match self.lock() {
334+
Ok(mut guard) => {
335+
*guard = value;
336+
337+
Ok(())
338+
}
339+
Err(_) => Err(PoisonError::new(value)),
340+
}
341+
}
342+
}
343+
344+
/// Replaces the contained value with `value`, and returns the old contained value.
345+
///
346+
/// # Errors
347+
///
348+
/// If another user of this mutex panicked while holding the mutex, then
349+
/// this call will return an error containing the provided `value` instead.
350+
///
351+
/// # Examples
352+
///
353+
/// ```
354+
/// #![feature(lock_value_accessors)]
355+
///
356+
/// use std::sync::Mutex;
357+
///
358+
/// let mut mutex = Mutex::new(7);
359+
///
360+
/// assert_eq!(mutex.replace(11).unwrap(), 7);
361+
/// assert_eq!(mutex.get_cloned().unwrap(), 11);
362+
/// ```
363+
#[unstable(feature = "lock_value_accessors", issue = "133407")]
364+
pub fn replace(&self, value: T) -> LockResult<T> {
365+
match self.lock() {
366+
Ok(mut guard) => Ok(mem::replace(&mut *guard, value)),
367+
Err(_) => Err(PoisonError::new(value)),
368+
}
369+
}
276370
}
277371

278372
impl<T: ?Sized> Mutex<T> {
@@ -290,7 +384,8 @@ impl<T: ?Sized> Mutex<T> {
290384
/// # Errors
291385
///
292386
/// If another user of this mutex panicked while holding the mutex, then
293-
/// this call will return an error once the mutex is acquired.
387+
/// this call will return an error once the mutex is acquired. The acquired
388+
/// mutex guard will be contained in the returned error.
294389
///
295390
/// # Panics
296391
///
@@ -331,7 +426,8 @@ impl<T: ?Sized> Mutex<T> {
331426
///
332427
/// If another user of this mutex panicked while holding the mutex, then
333428
/// this call will return the [`Poisoned`] error if the mutex would
334-
/// otherwise be acquired.
429+
/// otherwise be acquired. An acquired lock guard will be contained
430+
/// in the returned error.
335431
///
336432
/// If the mutex could not be acquired because it is already locked, then
337433
/// this call will return the [`WouldBlock`] error.
@@ -438,7 +534,8 @@ impl<T: ?Sized> Mutex<T> {
438534
/// # Errors
439535
///
440536
/// If another user of this mutex panicked while holding the mutex, then
441-
/// this call will return an error instead.
537+
/// this call will return an error containing the the underlying data
538+
/// instead.
442539
///
443540
/// # Examples
444541
///
@@ -465,7 +562,8 @@ impl<T: ?Sized> Mutex<T> {
465562
/// # Errors
466563
///
467564
/// If another user of this mutex panicked while holding the mutex, then
468-
/// this call will return an error instead.
565+
/// this call will return an error containing a mutable reference to the
566+
/// underlying data instead.
469567
///
470568
/// # Examples
471569
///

std/src/sync/mutex/tests.rs

+138-23
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
1+
use crate::fmt::Debug;
2+
use crate::ops::FnMut;
3+
use crate::panic::{self, AssertUnwindSafe};
14
use crate::sync::atomic::{AtomicUsize, Ordering};
25
use crate::sync::mpsc::channel;
36
use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
4-
use crate::thread;
7+
use crate::{hint, mem, thread};
58

69
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
710

811
#[derive(Eq, PartialEq, Debug)]
912
struct NonCopy(i32);
1013

14+
#[derive(Eq, PartialEq, Debug)]
15+
struct NonCopyNeedsDrop(i32);
16+
17+
impl Drop for NonCopyNeedsDrop {
18+
fn drop(&mut self) {
19+
hint::black_box(());
20+
}
21+
}
22+
23+
#[test]
24+
fn test_needs_drop() {
25+
assert!(!mem::needs_drop::<NonCopy>());
26+
assert!(mem::needs_drop::<NonCopyNeedsDrop>());
27+
}
28+
29+
#[derive(Clone, Eq, PartialEq, Debug)]
30+
struct Cloneable(i32);
31+
1132
#[test]
1233
fn smoke() {
1334
let m = Mutex::new(());
@@ -57,6 +78,21 @@ fn try_lock() {
5778
*m.try_lock().unwrap() = ();
5879
}
5980

81+
fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
82+
let mutex = Mutex::new(value);
83+
84+
let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| {
85+
let _guard = mutex.lock().unwrap();
86+
87+
panic!("test panic to poison mutex");
88+
}));
89+
90+
assert!(catch_unwind_result.is_err());
91+
assert!(mutex.is_poisoned());
92+
93+
mutex
94+
}
95+
6096
#[test]
6197
fn test_into_inner() {
6298
let m = Mutex::new(NonCopy(10));
@@ -83,21 +119,31 @@ fn test_into_inner_drop() {
83119

84120
#[test]
85121
fn test_into_inner_poison() {
86-
let m = Arc::new(Mutex::new(NonCopy(10)));
87-
let m2 = m.clone();
88-
let _ = thread::spawn(move || {
89-
let _lock = m2.lock().unwrap();
90-
panic!("test panic in inner thread to poison mutex");
91-
})
92-
.join();
122+
let m = new_poisoned_mutex(NonCopy(10));
93123

94-
assert!(m.is_poisoned());
95-
match Arc::try_unwrap(m).unwrap().into_inner() {
124+
match m.into_inner() {
96125
Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
97126
Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"),
98127
}
99128
}
100129

130+
#[test]
131+
fn test_get_cloned() {
132+
let m = Mutex::new(Cloneable(10));
133+
134+
assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
135+
}
136+
137+
#[test]
138+
fn test_get_cloned_poison() {
139+
let m = new_poisoned_mutex(Cloneable(10));
140+
141+
match m.get_cloned() {
142+
Err(e) => assert_eq!(e.into_inner(), ()),
143+
Ok(x) => panic!("get of poisoned Mutex is Ok: {x:?}"),
144+
}
145+
}
146+
101147
#[test]
102148
fn test_get_mut() {
103149
let mut m = Mutex::new(NonCopy(10));
@@ -107,21 +153,90 @@ fn test_get_mut() {
107153

108154
#[test]
109155
fn test_get_mut_poison() {
110-
let m = Arc::new(Mutex::new(NonCopy(10)));
111-
let m2 = m.clone();
112-
let _ = thread::spawn(move || {
113-
let _lock = m2.lock().unwrap();
114-
panic!("test panic in inner thread to poison mutex");
115-
})
116-
.join();
156+
let mut m = new_poisoned_mutex(NonCopy(10));
117157

118-
assert!(m.is_poisoned());
119-
match Arc::try_unwrap(m).unwrap().get_mut() {
158+
match m.get_mut() {
120159
Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
121160
Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"),
122161
}
123162
}
124163

164+
#[test]
165+
fn test_set() {
166+
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
167+
where
168+
T: Debug + Eq,
169+
{
170+
let m = Mutex::new(init());
171+
172+
assert_eq!(*m.lock().unwrap(), init());
173+
m.set(value()).unwrap();
174+
assert_eq!(*m.lock().unwrap(), value());
175+
}
176+
177+
inner(|| NonCopy(10), || NonCopy(20));
178+
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
179+
}
180+
181+
#[test]
182+
fn test_set_poison() {
183+
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
184+
where
185+
T: Debug + Eq,
186+
{
187+
let m = new_poisoned_mutex(init());
188+
189+
match m.set(value()) {
190+
Err(e) => {
191+
assert_eq!(e.into_inner(), value());
192+
assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
193+
}
194+
Ok(x) => panic!("set of poisoned Mutex is Ok: {x:?}"),
195+
}
196+
}
197+
198+
inner(|| NonCopy(10), || NonCopy(20));
199+
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
200+
}
201+
202+
#[test]
203+
fn test_replace() {
204+
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
205+
where
206+
T: Debug + Eq,
207+
{
208+
let m = Mutex::new(init());
209+
210+
assert_eq!(*m.lock().unwrap(), init());
211+
assert_eq!(m.replace(value()).unwrap(), init());
212+
assert_eq!(*m.lock().unwrap(), value());
213+
}
214+
215+
inner(|| NonCopy(10), || NonCopy(20));
216+
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
217+
}
218+
219+
#[test]
220+
fn test_replace_poison() {
221+
fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
222+
where
223+
T: Debug + Eq,
224+
{
225+
let m = new_poisoned_mutex(init());
226+
227+
match m.replace(value()) {
228+
Err(e) => {
229+
assert_eq!(e.into_inner(), value());
230+
assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
231+
}
232+
Ok(x) => panic!("replace of poisoned Mutex is Ok: {x:?}"),
233+
}
234+
}
235+
236+
inner(|| NonCopy(10), || NonCopy(20));
237+
inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
238+
}
239+
125240
#[test]
126241
fn test_mutex_arc_condvar() {
127242
let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
@@ -269,7 +384,7 @@ fn test_mapping_mapped_guard() {
269384
fn panic_while_mapping_unlocked_poison() {
270385
let lock = Mutex::new(());
271386

272-
let _ = crate::panic::catch_unwind(|| {
387+
let _ = panic::catch_unwind(|| {
273388
let guard = lock.lock().unwrap();
274389
let _guard = MutexGuard::map::<(), _>(guard, |_| panic!());
275390
});
@@ -282,7 +397,7 @@ fn panic_while_mapping_unlocked_poison() {
282397
Err(TryLockError::Poisoned(_)) => {}
283398
}
284399

285-
let _ = crate::panic::catch_unwind(|| {
400+
let _ = panic::catch_unwind(|| {
286401
let guard = lock.lock().unwrap();
287402
let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!());
288403
});
@@ -295,7 +410,7 @@ fn panic_while_mapping_unlocked_poison() {
295410
Err(TryLockError::Poisoned(_)) => {}
296411
}
297412

298-
let _ = crate::panic::catch_unwind(|| {
413+
let _ = panic::catch_unwind(|| {
299414
let guard = lock.lock().unwrap();
300415
let guard = MutexGuard::map::<(), _>(guard, |val| val);
301416
let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!());
@@ -309,7 +424,7 @@ fn panic_while_mapping_unlocked_poison() {
309424
Err(TryLockError::Poisoned(_)) => {}
310425
}
311426

312-
let _ = crate::panic::catch_unwind(|| {
427+
let _ = panic::catch_unwind(|| {
313428
let guard = lock.lock().unwrap();
314429
let guard = MutexGuard::map::<(), _>(guard, |val| val);
315430
let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!());

0 commit comments

Comments
 (0)