Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions readerwriterqueue.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ©2013-2020 Cameron Desrochers.
// ©2013-2020 Cameron Desrochers.
// Distributed under the simplified BSD license (see the license file that
// should have come with this header).

Expand Down Expand Up @@ -619,6 +619,13 @@ class MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE ReaderWriterQueue
newBlock->tail = newBlock->localTail = 1;

newBlock->next = tailBlock_->next.load();

// Publish all writes to *newBlock before it becomes reachable via either
// tailBlock_->next (walked by size_approx() and other chain traversals)
// or tailBlock itself (used by try_dequeue). Without this fence, on
// weakly-ordered architectures (e.g. AArch64) a reader could observe the
// updated `next` pointer before seeing newBlock's initialized fields.
fence(memory_order_release);
tailBlock_->next = newBlock;

// Might be possible for the dequeue thread to see the new tailBlock->next
Expand All @@ -627,7 +634,6 @@ class MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE ReaderWriterQueue
// case where it could try to read the next is if it's already at the tailBlock,
// and it won't advance past tailBlock in any circumstance).

Comment on lines 631 to 636

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment was to justify the previous placement of the fence, and can be removed, since it clearly missed a case in its reasoning :)

fence(memory_order_release);
tailBlock = newBlock;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need a release fence before setting tailBlock itself? Otherwise anything reading tailBlock might not see the latest value of tailBlock->next, which would be the opposite bug.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need a release fence before setting tailBlock itself? Otherwise anything reading tailBlock might not see the latest value of tailBlock->next, which would be the opposite bug.

Yeap, that is right. We need to guarantee that tailBlock's data was prepared before changing it.
I'll restore the second fence and clarify the comment accordingly.

}
else if (canAlloc == CannotAlloc) {
Expand Down