Skip to content

Commit fb33533

Browse files
committed
add potential solution pseudocode
1 parent 9f562f5 commit fb33533

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

library/std/src/sys/sync/rwlock/queue.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -479,31 +479,43 @@ impl RwLock {
479479
"RwLock should be LOCKED and QUEUED"
480480
);
481481

482+
// 1. Attempt to grab the queue lock
483+
// 2. Find the tail of the queue
484+
// 3. While the current tail is not a writer:
485+
// 4. The current tail must be a reader
486+
// 5. Remove the current tail from the queue and update the tail to be the previous
487+
// node if possible
488+
// 6. Set the flag (somewhere on the node) to notify the reader thread that it has
489+
// been woken up by a `downgrade` call
490+
// 7. `complete` the node
491+
// 8. Go back to step 3 with the updated tail if it exists, otherwise break
492+
// 9. Once we find a writer or there are no more `prev` links, we write the correct
493+
// number of readers into the current node state or the head state.
494+
495+
// Attempt to grab the queue lock.
496+
loop {
497+
// Atomically release the lock and try to acquire the queue lock.
498+
let next = state.map_addr(|addr| addr | QUEUE_LOCKED);
499+
match self.state.compare_exchange_weak(state & !QUEUE_LOCKED, next, AcqRel, Relaxed)
500+
{
501+
// The queue lock was acquired. Release it, waking up the next
502+
// waiter in the process.
503+
Ok(_) if state.addr() & QUEUE_LOCKED == 0 => unsafe {
504+
return self.unlock_queue(next);
505+
},
506+
// Another thread already holds the queue lock, leave waking up
507+
// waiters to it.
508+
Ok(_) => return,
509+
Err(new) => state = new,
510+
}
511+
}
512+
482513
// FIXME Is this correct?
483514
// SAFETY: Since we have the write lock, nobody else can be modifying state, and since
484515
// we got `state` from the `compare_exchange`, we know it is a valid head of the queue.
485516
let tail = unsafe { add_backlinks_and_find_tail(to_node(state)) };
486517

487-
// FIXME Is this safe to modify? There shouldn't be other threads modifying this since
488-
// we have the write lock and only we should be able to modify the nodes in the queue...
489-
// Increment the reader count from 0 to 1.
490-
let old = unsafe { tail.as_ref() }.next.0.fetch_byte_add(SINGLE, AcqRel).addr();
491-
debug_assert_eq!(old, 0, "Reader count was not zero while we had the write lock");
492-
493-
// Now that we are in read mode, traverse the queue and wake up readers until we find a
494-
// writer node.
495-
let mut current = tail;
496-
while unsafe { !current.as_ref().write } {
497-
let prev = unsafe { current.as_ref().prev.get() };
498-
unsafe {
499-
// There must be threads waiting.
500-
Node::complete(current);
501-
}
502-
match prev {
503-
Some(prev) => current = prev,
504-
None => return,
505-
}
506-
}
518+
todo!()
507519
}
508520
}
509521

0 commit comments

Comments
 (0)