Skip to content

Commit 454329e

Browse files
committed
first attempt at queue
1 parent d19e334 commit 454329e

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

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

+41-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,46 @@ impl RwLock {
453453

454454
#[inline]
455455
pub unsafe fn downgrade(&self) {
456-
todo!()
456+
// Atomically set to read-locked with a single reader, without any waiting threads.
457+
if let Err(mut state) = self.state.compare_exchange(
458+
without_provenance_mut(LOCKED),
459+
without_provenance_mut(LOCKED | SINGLE),
460+
Release,
461+
Relaxed,
462+
) {
463+
// Attempt to grab the queue lock.
464+
loop {
465+
let next = state.map_addr(|addr| addr | QUEUE_LOCKED);
466+
match self.state.compare_exchange(state, next, AcqRel, Relaxed) {
467+
Err(new_state) => state = new_state,
468+
Ok(new_state) => {
469+
assert_eq!(
470+
new_state.mask(!MASK).addr(),
471+
LOCKED | QUEUED | QUEUE_LOCKED,
472+
"{:p}",
473+
new_state
474+
);
475+
state = new_state;
476+
break;
477+
}
478+
}
479+
}
480+
481+
assert_eq!(state.mask(!MASK).addr(), LOCKED | QUEUED | QUEUE_LOCKED);
482+
483+
// SAFETY: We have the queue lock so all safety contracts are fulfilled.
484+
let tail = unsafe { add_backlinks_and_find_tail(to_node(state)).as_ref() };
485+
486+
// Increment the reader count from 0 to 1.
487+
assert_eq!(
488+
tail.next.0.fetch_byte_add(SINGLE, AcqRel).addr(),
489+
0,
490+
"Reader count was not zero while we had the write lock"
491+
);
492+
493+
// Release the queue lock.
494+
self.state.fetch_byte_sub(QUEUE_LOCKED, Release);
495+
}
457496
}
458497

459498
/// # Safety
@@ -547,6 +586,7 @@ impl RwLock {
547586
loop {
548587
let prev = unsafe { current.as_ref().prev.get() };
549588
unsafe {
589+
// There must be threads waiting.
550590
Node::complete(current);
551591
}
552592
match prev {

0 commit comments

Comments
 (0)