@@ -13,7 +13,9 @@ use prelude::v1::*;
13
13
use cell:: UnsafeCell ;
14
14
use fmt;
15
15
use marker;
16
+ use mem;
16
17
use ops:: { Deref , DerefMut } ;
18
+ use ptr;
17
19
use sys_common:: poison:: { self , LockResult , TryLockError , TryLockResult } ;
18
20
use sys_common:: rwlock as sys;
19
21
@@ -260,11 +262,60 @@ impl<T: ?Sized> RwLock<T> {
260
262
pub fn is_poisoned ( & self ) -> bool {
261
263
self . inner . poison . get ( )
262
264
}
265
+
266
+ /// Consumes this `RwLock`, returning the underlying data.
267
+ ///
268
+ /// # Failure
269
+ ///
270
+ /// This function will return an error if the RwLock is poisoned. An RwLock
271
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
272
+ /// error will only be returned if the lock would have otherwise been
273
+ /// acquired.
274
+ #[ unstable( feature = "rwlock_into_inner" , reason = "recently added" , issue = "28968" ) ]
275
+ pub fn into_inner ( self ) -> LockResult < T > where T : Sized {
276
+ // We know statically that there are no outstanding references to
277
+ // `self` so there's no need to lock the inner StaticRwLock.
278
+ //
279
+ // To get the inner value, we'd like to call `data.into_inner()`,
280
+ // but because `RwLock` impl-s `Drop`, we can't move out of it, so
281
+ // we'll have to destructure it manually instead.
282
+ unsafe {
283
+ // Like `let RwLock { inner, data } = self`.
284
+ let ( inner, data) = {
285
+ let RwLock { ref inner, ref data } = self ;
286
+ ( ptr:: read ( inner) , ptr:: read ( data) )
287
+ } ;
288
+ mem:: forget ( self ) ;
289
+ inner. lock . destroy ( ) ; // Keep in sync with the `Drop` impl.
290
+
291
+ poison:: map_result ( inner. poison . borrow ( ) , |_| data. into_inner ( ) )
292
+ }
293
+ }
294
+
295
+ /// Returns a mutable reference to the underlying data.
296
+ ///
297
+ /// Since this call borrows the `RwLock` mutably, no actual locking needs to
298
+ /// take place---the mutable borrow statically guarantees no locks exist.
299
+ ///
300
+ /// # Failure
301
+ ///
302
+ /// This function will return an error if the RwLock is poisoned. An RwLock
303
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
304
+ /// error will only be returned if the lock would have otherwise been
305
+ /// acquired.
306
+ #[ unstable( feature = "rwlock_get_mut" , reason = "recently added" , issue = "28968" ) ]
307
+ pub fn get_mut ( & mut self ) -> LockResult < & mut T > {
308
+ // We know statically that there are no other references to `self`, so
309
+ // there's no need to lock the inner StaticRwLock.
310
+ let data = unsafe { & mut * self . data . get ( ) } ;
311
+ poison:: map_result ( self . inner . poison . borrow ( ) , |_| data )
312
+ }
263
313
}
264
314
265
315
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
266
316
impl < T : ?Sized > Drop for RwLock < T > {
267
317
fn drop ( & mut self ) {
318
+ // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
268
319
unsafe { self . inner . lock . destroy ( ) }
269
320
}
270
321
}
@@ -426,6 +477,10 @@ mod tests {
426
477
use sync:: mpsc:: channel;
427
478
use thread;
428
479
use sync:: { Arc , RwLock , StaticRwLock , TryLockError } ;
480
+ use sync:: atomic:: { AtomicUsize , Ordering } ;
481
+
482
+ #[ derive( Eq , PartialEq , Debug ) ]
483
+ struct NonCopy ( i32 ) ;
429
484
430
485
#[ test]
431
486
fn smoke ( ) {
@@ -606,4 +661,67 @@ mod tests {
606
661
607
662
drop ( read_guard) ;
608
663
}
664
+
665
+ #[ test]
666
+ fn test_into_inner ( ) {
667
+ let m = RwLock :: new ( NonCopy ( 10 ) ) ;
668
+ assert_eq ! ( m. into_inner( ) . unwrap( ) , NonCopy ( 10 ) ) ;
669
+ }
670
+
671
+ #[ test]
672
+ fn test_into_inner_drop ( ) {
673
+ struct Foo ( Arc < AtomicUsize > ) ;
674
+ impl Drop for Foo {
675
+ fn drop ( & mut self ) {
676
+ self . 0 . fetch_add ( 1 , Ordering :: SeqCst ) ;
677
+ }
678
+ }
679
+ let num_drops = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
680
+ let m = RwLock :: new ( Foo ( num_drops. clone ( ) ) ) ;
681
+ assert_eq ! ( num_drops. load( Ordering :: SeqCst ) , 0 ) ;
682
+ {
683
+ let _inner = m. into_inner ( ) . unwrap ( ) ;
684
+ assert_eq ! ( num_drops. load( Ordering :: SeqCst ) , 0 ) ;
685
+ }
686
+ assert_eq ! ( num_drops. load( Ordering :: SeqCst ) , 1 ) ;
687
+ }
688
+
689
+ #[ test]
690
+ fn test_into_inner_poison ( ) {
691
+ let m = Arc :: new ( RwLock :: new ( NonCopy ( 10 ) ) ) ;
692
+ let m2 = m. clone ( ) ;
693
+ let _ = thread:: spawn ( move || {
694
+ let _lock = m2. write ( ) . unwrap ( ) ;
695
+ panic ! ( "test panic in inner thread to poison RwLock" ) ;
696
+ } ) . join ( ) ;
697
+
698
+ assert ! ( m. is_poisoned( ) ) ;
699
+ match Arc :: try_unwrap ( m) . unwrap ( ) . into_inner ( ) {
700
+ Err ( e) => assert_eq ! ( e. into_inner( ) , NonCopy ( 10 ) ) ,
701
+ Ok ( x) => panic ! ( "into_inner of poisoned RwLock is Ok: {:?}" , x) ,
702
+ }
703
+ }
704
+
705
+ #[ test]
706
+ fn test_get_mut ( ) {
707
+ let mut m = RwLock :: new ( NonCopy ( 10 ) ) ;
708
+ * m. get_mut ( ) . unwrap ( ) = NonCopy ( 20 ) ;
709
+ assert_eq ! ( m. into_inner( ) . unwrap( ) , NonCopy ( 20 ) ) ;
710
+ }
711
+
712
+ #[ test]
713
+ fn test_get_mut_poison ( ) {
714
+ let m = Arc :: new ( RwLock :: new ( NonCopy ( 10 ) ) ) ;
715
+ let m2 = m. clone ( ) ;
716
+ let _ = thread:: spawn ( move || {
717
+ let _lock = m2. write ( ) . unwrap ( ) ;
718
+ panic ! ( "test panic in inner thread to poison RwLock" ) ;
719
+ } ) . join ( ) ;
720
+
721
+ assert ! ( m. is_poisoned( ) ) ;
722
+ match Arc :: try_unwrap ( m) . unwrap ( ) . get_mut ( ) {
723
+ Err ( e) => assert_eq ! ( * e. into_inner( ) , NonCopy ( 10 ) ) ,
724
+ Ok ( x) => panic ! ( "get_mut of poisoned RwLock is Ok: {:?}" , x) ,
725
+ }
726
+ }
609
727
}
0 commit comments