Commit 6a80914d authored by Nick Sukhanov's avatar Nick Sukhanov Committed by Facebook Github Bot

Make `next` relaxed

Summary: We had a rare data race on next this diff is fixing that.

Reviewed By: yfeldblum

Differential Revision: D15120382

fbshipit-source-id: d3f0e521b941fdfcd1d968a42d7e8d240c3f74e6
parent 15666e6a
...@@ -127,19 +127,25 @@ struct LifoSemRawNode { ...@@ -127,19 +127,25 @@ struct LifoSemRawNode {
/// The IndexedMemPool index of the next node in this chain, or 0 /// The IndexedMemPool index of the next node in this chain, or 0
/// if none. This will be set to uint32_t(-1) if the node is being /// if none. This will be set to uint32_t(-1) if the node is being
/// posted due to a shutdown-induced wakeup /// posted due to a shutdown-induced wakeup
uint32_t next; Atom<uint32_t> next{0};
bool isShutdownNotice() const { bool isShutdownNotice() const {
return next == uint32_t(-1); return next.load(std::memory_order_relaxed) == uint32_t(-1);
} }
void clearShutdownNotice() { void clearShutdownNotice() {
next = 0; next.store(0, std::memory_order_relaxed);
} }
void setShutdownNotice() { void setShutdownNotice() {
next = uint32_t(-1); next.store(uint32_t(-1), std::memory_order_relaxed);
} }
typedef folly::IndexedMemPool<LifoSemRawNode<Atom>, 32, 200, Atom> Pool; typedef folly::IndexedMemPool<
LifoSemRawNode<Atom>,
32,
200,
Atom,
IndexedMemPoolTraitsLazyRecycle<LifoSemRawNode<Atom>>>
Pool;
/// Storage for all of the waiter nodes for LifoSem-s that use Atom /// Storage for all of the waiter nodes for LifoSem-s that use Atom
static Pool& pool(); static Pool& pool();
...@@ -422,7 +428,7 @@ struct LifoSemBase { ...@@ -422,7 +428,7 @@ struct LifoSemBase {
continue; continue;
} }
auto& node = idxToNode(h.idx()); auto& node = idxToNode(h.idx());
auto repl = h.withPop(node.next); auto repl = h.withPop(node.next.load(std::memory_order_relaxed));
if (head_->compare_exchange_strong(h, repl)) { if (head_->compare_exchange_strong(h, repl)) {
// successful pop, wake up the waiter and move on. The next // successful pop, wake up the waiter and move on. The next
// field is used to convey that this wakeup didn't consume a value // field is used to convey that this wakeup didn't consume a value
...@@ -630,20 +636,23 @@ struct LifoSemBase { ...@@ -630,20 +636,23 @@ struct LifoSemBase {
if (idx == removeidx) { if (idx == removeidx) {
// pop from head. Head seqno is updated. // pop from head. Head seqno is updated.
head_->store( head_->store(
head.withoutLock(removenode.next), std::memory_order_release); head.withoutLock(removenode.next.load(std::memory_order_relaxed)),
std::memory_order_release);
return true; return true;
} }
auto node = &idxToNode(idx); auto node = &idxToNode(idx);
idx = node->next; idx = node->next.load(std::memory_order_relaxed);
while (idx) { while (idx) {
if (idx == removeidx) { if (idx == removeidx) {
// Pop from mid-list. // Pop from mid-list.
node->next = removenode.next; node->next.store(
removenode.next.load(std::memory_order_relaxed),
std::memory_order_relaxed);
result = true; result = true;
break; break;
} }
node = &idxToNode(idx); node = &idxToNode(idx);
idx = node->next; idx = node->next.load(std::memory_order_relaxed);
} }
// Unlock and return result // Unlock and return result
head_->store(head.withoutLock(head.idx()), std::memory_order_release); head_->store(head.withoutLock(head.idx()), std::memory_order_release);
...@@ -664,7 +673,9 @@ struct LifoSemBase { ...@@ -664,7 +673,9 @@ struct LifoSemBase {
} }
if (head.isNodeIdx()) { if (head.isNodeIdx()) {
auto& node = idxToNode(head.idx()); auto& node = idxToNode(head.idx());
if (head_->compare_exchange_strong(head, head.withPop(node.next))) { if (head_->compare_exchange_strong(
head,
head.withPop(node.next.load(std::memory_order_relaxed)))) {
// successful pop // successful pop
return head.idx(); return head.idx();
} }
...@@ -715,7 +726,8 @@ struct LifoSemBase { ...@@ -715,7 +726,8 @@ struct LifoSemBase {
} }
auto& node = idxToNode(idx); auto& node = idxToNode(idx);
node.next = head.isNodeIdx() ? head.idx() : 0; node.next.store(
head.isNodeIdx() ? head.idx() : 0, std::memory_order_relaxed);
if (head_->compare_exchange_strong(head, head.withPush(idx))) { if (head_->compare_exchange_strong(head, head.withPush(idx))) {
// push succeeded // push succeeded
return WaitResult::PUSH; return WaitResult::PUSH;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment