Skip to content

Commit

Permalink
Store the debt list as pointers, not refs
Browse files Browse the repository at this point in the history
The idea is that the whole list (tail of the list) is synchronized by
the access of the head. Nevertheless, we fill in the next pointer before
that and having a reference is formally considered a read of the
destination. Even though we _use_ the reference only after the
synchronization point, we have it before and MIRI considers it a data
race.

Using a pointer is fine, as dereferencing is manual and considered read
only at that point.
  • Loading branch information
vorner committed Dec 25, 2022
1 parent fd04e20 commit 56951c8
Showing 1 changed file with 9 additions and 4 deletions.
13 changes: 9 additions & 4 deletions src/debt/list.rs
Expand Up @@ -58,7 +58,12 @@ pub(crate) struct Node {
fast: FastSlots,
helping: HelpingSlots,
in_use: AtomicUsize,
next: Option<&'static Node>,
// Next node in the list.
//
// It is a pointer because we touch it before synchronization (we don't _dereference_ it before
// synchronization, only manipulate the pointer itself). That is illegal according to strict
// interpretation of the rules by MIRI on references.
next: *const Node,
active_writers: AtomicUsize,
}

Expand All @@ -68,7 +73,7 @@ impl Default for Node {
fast: FastSlots::default(),
helping: HelpingSlots::default(),
in_use: AtomicUsize::new(NODE_USED),
next: None,
next: ptr::null(),
active_writers: AtomicUsize::new(0),
}
}
Expand All @@ -94,7 +99,7 @@ impl Node {
if result.is_some() {
return result;
}
current = node.next;
current = unsafe { node.next.as_ref() };
}
None
}
Expand Down Expand Up @@ -165,7 +170,7 @@ impl Node {
// compare_exchange below.
let mut head = LIST_HEAD.load(Relaxed);
loop {
node.next = unsafe { head.as_ref() };
node.next = head;
if let Err(old) = LIST_HEAD.compare_exchange_weak(
head, node,
// We need to release *the whole chain* here. For that, we need to
Expand Down

0 comments on commit 56951c8

Please sign in to comment.