@@ -517,14 +517,16 @@ impl<T> Lock<T> {
517
517
}
518
518
519
519
// The lock was successfully acquired.
520
- Poll :: Ready ( LockGuard ( self . 0 . clone ( ) ) )
520
+ Poll :: Ready ( LockGuard ( Some ( self . 0 . clone ( ) ) ) )
521
521
}
522
522
}
523
523
524
524
/// A lock guard.
525
525
///
526
526
/// When dropped, ownership of the inner value is returned back to the lock.
527
- struct LockGuard < T > ( Arc < LockState < T > > ) ;
527
+ /// The inner value is always Some, except when the lock is dropped, where we
528
+ /// set it to None. See comment in drop().
529
+ struct LockGuard < T > ( Option < Arc < LockState < T > > > ) ;
528
530
529
531
unsafe impl < T : Send > Send for LockGuard < T > { }
530
532
unsafe impl < T : Sync > Sync for LockGuard < T > { }
@@ -534,7 +536,7 @@ impl<T> LockGuard<T> {
534
536
///
535
537
/// When this lock guard gets dropped, all registered tasks will be woken up.
536
538
fn register ( & self , cx : & Context < ' _ > ) {
537
- let mut list = self . 0 . wakers . lock ( ) . unwrap ( ) ;
539
+ let mut list = self . 0 . as_ref ( ) . unwrap ( ) . wakers . lock ( ) . unwrap ( ) ;
538
540
539
541
if list. iter ( ) . all ( |w| !w. will_wake ( cx. waker ( ) ) ) {
540
542
list. push ( cx. waker ( ) . clone ( ) ) ;
@@ -544,11 +546,22 @@ impl<T> LockGuard<T> {
544
546
545
547
impl < T > Drop for LockGuard < T > {
546
548
fn drop ( & mut self ) {
549
+ // Set the Option to None and take its value so we can drop the Arc
550
+ // before we wake up the tasks.
551
+ let lock = self . 0 . take ( ) . unwrap ( ) ;
552
+
553
+ // Prepare to wake up all registered tasks interested in acquiring the lock.
554
+ let wakers: Vec < _ > = lock. wakers . lock ( ) . unwrap ( ) . drain ( ..) . collect ( ) ;
555
+
547
556
// Release the lock.
548
- self . 0 . locked . store ( false , Ordering :: Release ) ;
557
+ lock. locked . store ( false , Ordering :: Release ) ;
558
+
559
+ // Drop the Arc _before_ waking up the tasks, to avoid races. See
560
+ // reproducer and discussion in https://github.com/async-rs/async-std/issues/1001.
561
+ drop ( lock) ;
549
562
550
563
// Wake up all registered tasks interested in acquiring the lock.
551
- for w in self . 0 . wakers . lock ( ) . unwrap ( ) . drain ( .. ) {
564
+ for w in wakers {
552
565
w. wake ( ) ;
553
566
}
554
567
}
@@ -558,13 +571,19 @@ impl<T> Deref for LockGuard<T> {
558
571
type Target = T ;
559
572
560
573
fn deref ( & self ) -> & T {
561
- unsafe { & * self . 0 . value . get ( ) }
574
+ // SAFETY: Safe because the lock is held when this method is called. And
575
+ // the inner value is always Some since it is only set to None in
576
+ // drop().
577
+ unsafe { & * self . 0 . as_ref ( ) . unwrap ( ) . value . get ( ) }
562
578
}
563
579
}
564
580
565
581
impl < T > DerefMut for LockGuard < T > {
566
582
fn deref_mut ( & mut self ) -> & mut T {
567
- unsafe { & mut * self . 0 . value . get ( ) }
583
+ // SAFETY: Safe because the lock is held when this method is called. And
584
+ // the inner value is always Some since it is only set to None in
585
+ // drop().
586
+ unsafe { & mut * self . 0 . as_ref ( ) . unwrap ( ) . value . get ( ) }
568
587
}
569
588
}
570
589
0 commit comments