@@ -517,14 +517,16 @@ impl<T> Lock<T> {
517517 }
518518
519519 // The lock was successfully acquired.
520- Poll :: Ready ( LockGuard ( self . 0 . clone ( ) ) )
520+ Poll :: Ready ( LockGuard ( Some ( self . 0 . clone ( ) ) ) )
521521 }
522522}
523523
524524/// A lock guard.
525525///
526526/// 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 > > > ) ;
528530
529531unsafe impl < T : Send > Send for LockGuard < T > { }
530532unsafe impl < T : Sync > Sync for LockGuard < T > { }
@@ -534,7 +536,7 @@ impl<T> LockGuard<T> {
534536 ///
535537 /// When this lock guard gets dropped, all registered tasks will be woken up.
536538 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 ( ) ;
538540
539541 if list. iter ( ) . all ( |w| !w. will_wake ( cx. waker ( ) ) ) {
540542 list. push ( cx. waker ( ) . clone ( ) ) ;
@@ -544,11 +546,22 @@ impl<T> LockGuard<T> {
544546
545547impl < T > Drop for LockGuard < T > {
546548 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+
547556 // 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) ;
549562
550563 // 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 {
552565 w. wake ( ) ;
553566 }
554567 }
@@ -558,13 +571,19 @@ impl<T> Deref for LockGuard<T> {
558571 type Target = T ;
559572
560573 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 ( ) }
562578 }
563579}
564580
565581impl < T > DerefMut for LockGuard < T > {
566582 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 ( ) }
568587 }
569588}
570589
0 commit comments