@@ -476,16 +476,22 @@ impl RwLock {
476476 }
477477 }
478478
479+ /// # Safety
480+ ///
481+ /// * There must be threads queued on the lock.
482+ /// * `state` must be a pointer to a node in a valid queue.
483+ /// * There cannot be a `downgrade` in progress.
479484 #[ cold]
480485 unsafe fn read_unlock_contended ( & self , state : State ) {
481- // The state was observed with acquire ordering above, so the current
482- // thread will observe all node initializations.
483-
484- // FIXME this is a bit confusing
485- // SAFETY: Because new read-locks cannot be acquired while threads are queued, all
486- // queue-lock owners will observe the set `LOCKED` bit. And because no downgrade can be in
487- // progress (we checked above), they hence do not modify the queue, so the queue will not be
488- // removed from here.
486+ // SAFETY:
487+ // The state was observed with acquire ordering above, so the current thread will have
488+ // observed all node initializations.
489+ // We also know that no threads can be modifying the queue starting at `state`: because new
490+ // read-locks cannot be acquired while there are any threads queued on the lock, all
491+ // queue-lock owners will observe a set `LOCKED` bit in `self.state` and will not modify
492+ // the queue. The other case that a thread could modify the queue is if a downgrade is in
493+ // progress (removal of the entire queue), but since that is part of this function's safety
494+ // contract, we can guarantee that no other threads can modify the queue.
489495 let tail = unsafe { find_tail_and_add_backlinks ( to_node ( state) ) . as_ref ( ) } ;
490496
491497 // The lock count is stored in the `next` field of `tail`.
@@ -515,10 +521,11 @@ impl RwLock {
515521 ///
516522 /// * The lock must be exclusively owned by this thread.
517523 /// * There must be threads queued on the lock.
524+ /// * `state` must be a pointer to a node in a valid queue.
518525 /// * There cannot be a `downgrade` in progress.
519526 #[ cold]
520527 unsafe fn unlock_contended ( & self , state : State ) {
521- debug_assert ! ( state. addr( ) & STATE == ( QUEUED | LOCKED ) ) ;
528+ debug_assert_eq ! ( state. addr( ) & ( DOWNGRADED | QUEUED | LOCKED ) , QUEUED | LOCKED ) ;
522529
523530 let mut current = state;
524531
@@ -540,9 +547,10 @@ impl RwLock {
540547 // Atomically release the lock and try to acquire the queue lock.
541548 let next = current. map_addr ( |addr| ( addr & !LOCKED ) | QUEUE_LOCKED ) ;
542549 match self . state . compare_exchange_weak ( current, next, AcqRel , Relaxed ) {
550+ // Now that we have the queue lock, we can wake up the next waiter.
543551 Ok ( _) => {
544- // Now that we have the queue lock, we can wake up the next waiter.
545- // SAFETY: This thread is exclusively owned by this thread .
552+ // SAFETY: This thread just acquired the queue lock, and this function's safety
553+ // contract requires that there are threads already queued on the lock .
546554 unsafe { self . unlock_queue ( next) } ;
547555 return ;
548556 }
@@ -580,10 +588,11 @@ impl RwLock {
580588 /// # Safety
581589 ///
582590 /// * The lock must be write-locked by this thread.
591+ /// * `state` must be a pointer to a node in a valid queue.
583592 /// * There must be threads queued on the lock.
584593 #[ cold]
585594 unsafe fn downgrade_slow ( & self , mut state : State ) {
586- debug_assert ! ( state. addr( ) & ( DOWNGRADED | QUEUED | LOCKED ) == ( QUEUED | LOCKED ) ) ;
595+ debug_assert_eq ! ( state. addr( ) & ( DOWNGRADED | QUEUED | LOCKED ) , QUEUED | LOCKED ) ;
587596
588597 // Attempt to wake up all waiters by taking ownership of the entire waiter queue.
589598 loop {
@@ -612,7 +621,8 @@ impl RwLock {
612621 let tail = unsafe { find_tail_and_add_backlinks ( to_node ( state) ) } ;
613622
614623 // Wake up all waiters.
615- // SAFETY: `tail` was just computed, meaning the whole queue is linked.
624+ // SAFETY: `tail` was just computed, meaning the whole queue is linked, and we have
625+ // full ownership of the queue, so we have exclusive access.
616626 unsafe { complete_all ( tail) } ;
617627
618628 return ;
@@ -626,11 +636,13 @@ impl RwLock {
626636 /// # Safety
627637 ///
628638 /// * The queue lock must be held by the current thread.
639+ /// * `state` must be a pointer to a node in a valid queue.
629640 /// * There must be threads queued on the lock.
630641 unsafe fn unlock_queue ( & self , mut state : State ) {
631642 debug_assert_eq ! ( state. addr( ) & ( QUEUED | QUEUE_LOCKED ) , QUEUED | QUEUE_LOCKED ) ;
632643
633644 loop {
645+ // SAFETY: Since we have the queue lock, nobody else can be modifying the queue.
634646 let tail = unsafe { find_tail_and_add_backlinks ( to_node ( state) ) } ;
635647
636648 if state. addr ( ) & ( DOWNGRADED | LOCKED ) == LOCKED {
0 commit comments