Commit f4d97dc6 authored by Maged Michael's avatar Maged Michael Committed by Facebook Github Bot

UnboundedQueue: Change try_dequeue variants to fail only if the queue is empty

Summary:
The current semantics of try_dequeue variants can cause problems in cases where based on external dependencies the consumer is guaranteed that the queue is not empty and depends on the success of try_dequeue. See https://github.com/facebook/wangle/commit/abd07a06cae09efcd4347a9a019d59ae8a013c3f

This diff changes the semantics so that try_dequeue operations fail only if the queue is empty.

Reviewed By: yfeldblum

Differential Revision: D6586156

fbshipit-source-id: 25d6085e28d3e24034ecf6a8bafab51c95464b01
parent 124efa23
...@@ -377,11 +377,11 @@ class UnboundedQueue { ...@@ -377,11 +377,11 @@ class UnboundedQueue {
// possible to call ~T() and it may happen to use hazard pointers. // possible to call ~T() and it may happen to use hazard pointers.
folly::hazptr::hazptr_holder hptr; folly::hazptr::hazptr_holder hptr;
Segment* s = hptr.get_protected(c_.head); Segment* s = hptr.get_protected(c_.head);
return ryDequeueUntilMC(s, item, deadline); return tryDequeueUntilMC(s, item, deadline);
} }
} }
/** ryDequeueUntilSC */ /** tryDequeueUntilSC */
template <typename Clock, typename Duration> template <typename Clock, typename Duration>
FOLLY_ALWAYS_INLINE bool tryDequeueUntilSC( FOLLY_ALWAYS_INLINE bool tryDequeueUntilSC(
Segment* s, Segment* s,
...@@ -392,7 +392,7 @@ class UnboundedQueue { ...@@ -392,7 +392,7 @@ class UnboundedQueue {
DCHECK_LT(t, (s->minTicket() + SegmentSize)); DCHECK_LT(t, (s->minTicket() + SegmentSize));
size_t idx = index(t); size_t idx = index(t);
Entry& e = s->entry(idx); Entry& e = s->entry(idx);
if (!e.tryWaitUntil(deadline)) { if (UNLIKELY(!tryDequeueWaitElem(e, t, deadline))) {
return false; return false;
} }
setConsumerTicket(t + 1); setConsumerTicket(t + 1);
...@@ -405,7 +405,7 @@ class UnboundedQueue { ...@@ -405,7 +405,7 @@ class UnboundedQueue {
/** tryDequeueUntilMC */ /** tryDequeueUntilMC */
template <typename Clock, typename Duration> template <typename Clock, typename Duration>
FOLLY_ALWAYS_INLINE bool ryDequeueUntilMC( FOLLY_ALWAYS_INLINE bool tryDequeueUntilMC(
Segment* s, Segment* s,
T& item, T& item,
const std::chrono::time_point<Clock, Duration>& deadline) noexcept { const std::chrono::time_point<Clock, Duration>& deadline) noexcept {
...@@ -420,7 +420,7 @@ class UnboundedQueue { ...@@ -420,7 +420,7 @@ class UnboundedQueue {
} }
size_t idx = index(t); size_t idx = index(t);
Entry& e = s->entry(idx); Entry& e = s->entry(idx);
if (!e.tryWaitUntil(deadline)) { if (UNLIKELY(!tryDequeueWaitElem(e, t, deadline))) {
return false; return false;
} }
if (!c_.ticket.compare_exchange_weak( if (!c_.ticket.compare_exchange_weak(
...@@ -435,6 +435,23 @@ class UnboundedQueue { ...@@ -435,6 +435,23 @@ class UnboundedQueue {
} }
} }
/** tryDequeueWaitElem */
template <typename Clock, typename Duration>
FOLLY_ALWAYS_INLINE bool tryDequeueWaitElem(
Entry& e,
Ticket t,
const std::chrono::time_point<Clock, Duration>& deadline) noexcept {
while (true) {
if (LIKELY(e.tryWaitUntil(deadline))) {
return true;
}
if (t >= producerTicket()) {
return false;
}
asm_volatile_pause();
}
}
/** findSegment */ /** findSegment */
FOLLY_ALWAYS_INLINE FOLLY_ALWAYS_INLINE
Segment* findSegment(Segment* s, const Ticket t) const noexcept { Segment* findSegment(Segment* s, const Ticket t) const noexcept {
......
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