@@ -172,7 +172,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
172
172
// funny underscores due to how Deref/DerefMut currently work (they
173
173
// disregard field privacy).
174
174
__lock : & ' a StaticMutex ,
175
- __data : & ' a UnsafeCell < T > ,
175
+ __data : & ' a mut T ,
176
176
__poison : poison:: Guard ,
177
177
}
178
178
@@ -211,8 +211,10 @@ impl<T: ?Sized> Mutex<T> {
211
211
/// this call will return an error once the mutex is acquired.
212
212
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
213
213
pub fn lock ( & self ) -> LockResult < MutexGuard < T > > {
214
- unsafe { self . inner . lock . lock ( ) }
215
- MutexGuard :: new ( & * self . inner , & self . data )
214
+ unsafe {
215
+ self . inner . lock . lock ( ) ;
216
+ MutexGuard :: new ( & * self . inner , & self . data )
217
+ }
216
218
}
217
219
218
220
/// Attempts to acquire this lock.
@@ -230,10 +232,12 @@ impl<T: ?Sized> Mutex<T> {
230
232
/// acquired.
231
233
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
232
234
pub fn try_lock ( & self ) -> TryLockResult < MutexGuard < T > > {
233
- if unsafe { self . inner . lock . try_lock ( ) } {
234
- Ok ( try!( MutexGuard :: new ( & * self . inner , & self . data ) ) )
235
- } else {
236
- Err ( TryLockError :: WouldBlock )
235
+ unsafe {
236
+ if self . inner . lock . try_lock ( ) {
237
+ Ok ( try!( MutexGuard :: new ( & * self . inner , & self . data ) ) )
238
+ } else {
239
+ Err ( TryLockError :: WouldBlock )
240
+ }
237
241
}
238
242
}
239
243
@@ -338,17 +342,21 @@ impl StaticMutex {
338
342
/// Acquires this lock, see `Mutex::lock`
339
343
#[ inline]
340
344
pub fn lock ( & ' static self ) -> LockResult < MutexGuard < ( ) > > {
341
- unsafe { self . lock . lock ( ) }
342
- MutexGuard :: new ( self , & DUMMY . 0 )
345
+ unsafe {
346
+ self . lock . lock ( ) ;
347
+ MutexGuard :: new ( self , & DUMMY . 0 )
348
+ }
343
349
}
344
350
345
351
/// Attempts to grab this lock, see `Mutex::try_lock`
346
352
#[ inline]
347
353
pub fn try_lock ( & ' static self ) -> TryLockResult < MutexGuard < ( ) > > {
348
- if unsafe { self . lock . try_lock ( ) } {
349
- Ok ( try!( MutexGuard :: new ( self , & DUMMY . 0 ) ) )
350
- } else {
351
- Err ( TryLockError :: WouldBlock )
354
+ unsafe {
355
+ if self . lock . try_lock ( ) {
356
+ Ok ( try!( MutexGuard :: new ( self , & DUMMY . 0 ) ) )
357
+ } else {
358
+ Err ( TryLockError :: WouldBlock )
359
+ }
352
360
}
353
361
}
354
362
@@ -369,32 +377,72 @@ impl StaticMutex {
369
377
370
378
impl < ' mutex , T : ?Sized > MutexGuard < ' mutex , T > {
371
379
372
- fn new ( lock : & ' mutex StaticMutex , data : & ' mutex UnsafeCell < T > )
380
+ unsafe fn new ( lock : & ' mutex StaticMutex , data : & ' mutex UnsafeCell < T > )
373
381
-> LockResult < MutexGuard < ' mutex , T > > {
374
382
poison:: map_result ( lock. poison . borrow ( ) , |guard| {
375
383
MutexGuard {
376
384
__lock : lock,
377
- __data : data,
385
+ __data : & mut * data. get ( ) ,
378
386
__poison : guard,
379
387
}
380
388
} )
381
389
}
390
+
391
+ /// Transform this guard to hold a sub-borrow of the original data.
392
+ ///
393
+ /// Applies the supplied closure to the data, returning a new lock
394
+ /// guard referencing the borrow returned by the closure.
395
+ ///
396
+ /// # Examples
397
+ ///
398
+ /// ```rust
399
+ /// # #![feature(guard_map)]
400
+ /// # use std::sync::{Mutex, MutexGuard};
401
+ /// let x = Mutex::new(vec![1, 2]);
402
+ ///
403
+ /// {
404
+ /// let mut y = MutexGuard::map(x.lock().unwrap(), |v| &mut v[0]);
405
+ /// *y = 3;
406
+ /// }
407
+ ///
408
+ /// assert_eq!(&*x.lock().unwrap(), &[3, 2]);
409
+ /// ```
410
+ #[ unstable( feature = "guard_map" ,
411
+ reason = "recently added, needs RFC for stabilization" ,
412
+ issue = "27746" ) ]
413
+ pub fn map < U : ?Sized , F > ( this : Self , cb : F ) -> MutexGuard < ' mutex , U >
414
+ where F : FnOnce ( & ' mutex mut T ) -> & ' mutex mut U
415
+ {
416
+ // Compute the new data while still owning the original lock
417
+ // in order to correctly poison if the callback panics.
418
+ let data = unsafe { ptr:: read ( & this. __data ) } ;
419
+ let new_data = cb ( data) ;
420
+
421
+ // We don't want to unlock the lock by running the destructor of the
422
+ // original lock, so just read the fields we need and forget it.
423
+ let ( poison, lock) = unsafe {
424
+ ( ptr:: read ( & this. __poison ) , ptr:: read ( & this. __lock ) )
425
+ } ;
426
+ mem:: forget ( this) ;
427
+
428
+ MutexGuard {
429
+ __lock : lock,
430
+ __data : new_data,
431
+ __poison : poison
432
+ }
433
+ }
382
434
}
383
435
384
436
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
385
437
impl < ' mutex , T : ?Sized > Deref for MutexGuard < ' mutex , T > {
386
438
type Target = T ;
387
439
388
- fn deref ( & self ) -> & T {
389
- unsafe { & * self . __data . get ( ) }
390
- }
440
+ fn deref ( & self ) -> & T { self . __data }
391
441
}
392
442
393
443
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
394
444
impl < ' mutex , T : ?Sized > DerefMut for MutexGuard < ' mutex , T > {
395
- fn deref_mut ( & mut self ) -> & mut T {
396
- unsafe { & mut * self . __data . get ( ) }
397
- }
445
+ fn deref_mut ( & mut self ) -> & mut T { self . __data }
398
446
}
399
447
400
448
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -421,7 +469,7 @@ mod tests {
421
469
use prelude:: v1:: * ;
422
470
423
471
use sync:: mpsc:: channel;
424
- use sync:: { Arc , Mutex , StaticMutex , Condvar } ;
472
+ use sync:: { Arc , Mutex , StaticMutex , Condvar , MutexGuard } ;
425
473
use sync:: atomic:: { AtomicUsize , Ordering } ;
426
474
use thread;
427
475
@@ -665,4 +713,19 @@ mod tests {
665
713
let comp: & [ i32 ] = & [ 4 , 2 , 5 ] ;
666
714
assert_eq ! ( & * mutex. lock( ) . unwrap( ) , comp) ;
667
715
}
716
+
717
+ #[ test]
718
+ fn test_mutex_guard_map_panic ( ) {
719
+ let mutex = Arc :: new ( Mutex :: new ( vec ! [ 1 , 2 ] ) ) ;
720
+ let mutex2 = mutex. clone ( ) ;
721
+
722
+ thread:: spawn ( move || {
723
+ let _ = MutexGuard :: map :: < usize , _ > ( mutex2. lock ( ) . unwrap ( ) , |_| panic ! ( ) ) ;
724
+ } ) . join ( ) . unwrap_err ( ) ;
725
+
726
+ match mutex. lock ( ) {
727
+ Ok ( r) => panic ! ( "Lock on poisioned Mutex is Ok: {:?}" , & * r) ,
728
+ Err ( _) => { }
729
+ } ;
730
+ }
668
731
}
0 commit comments