Commit f0d42801 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Fix waiting in Baton, SaturatingSemaphore

Summary:
[Folly] Fix waiting in `Baton`, `SaturatingSemaphore`.

If condition passes or overall deadline expires, just return. If only a component timeout expires, continue on to the next component.

Reviewed By: magedm

Differential Revision: D7151564

fbshipit-source-id: 48c33ccc6970604b23221bc94af247945bdc34e5
parent af978f69
......@@ -263,13 +263,24 @@ class Baton {
FOLLY_NOINLINE bool tryWaitSlow(
const std::chrono::time_point<Clock, Duration>& deadline,
const WaitOptions& opt) noexcept {
if (detail::spin_pause_until(deadline, opt, [=] { return ready(); })) {
assert(ready());
return true;
switch (detail::spin_pause_until(deadline, opt, [=] { return ready(); })) {
case detail::spin_result::success:
return true;
case detail::spin_result::timeout:
return false;
case detail::spin_result::advance:
break;
}
if (!MayBlock) {
return detail::spin_yield_until(deadline, [=] { return ready(); });
switch (detail::spin_yield_until(deadline, [=] { return ready(); })) {
case detail::spin_result::success:
return true;
case detail::spin_result::timeout:
return false;
case detail::spin_result::advance:
break;
}
}
// guess we have to block :(
......
......@@ -280,12 +280,24 @@ template <typename Clock, typename Duration>
FOLLY_NOINLINE bool SaturatingSemaphore<MayBlock, Atom>::tryWaitSlow(
const std::chrono::time_point<Clock, Duration>& deadline,
const WaitOptions& opt) noexcept {
if (detail::spin_pause_until(deadline, opt, [=] { return ready(); })) {
return true;
switch (detail::spin_pause_until(deadline, opt, [=] { return ready(); })) {
case detail::spin_result::success:
return true;
case detail::spin_result::timeout:
return false;
case detail::spin_result::advance:
break;
}
if (!MayBlock) {
return detail::spin_yield_until(deadline, [=] { return ready(); });
switch (detail::spin_yield_until(deadline, [=] { return ready(); })) {
case detail::spin_result::success:
return true;
case detail::spin_result::timeout:
return false;
case detail::spin_result::advance:
break;
}
}
auto before = state_.load(std::memory_order_relaxed);
......
......@@ -26,30 +26,36 @@
namespace folly {
namespace detail {
enum class spin_result {
success, // condition passed
timeout, // exceeded deadline
advance, // exceeded current wait-options component timeout
};
template <typename Clock, typename Duration, typename F>
bool spin_pause_until(
spin_result spin_pause_until(
std::chrono::time_point<Clock, Duration> const& deadline,
WaitOptions const& opt,
F f) {
if (opt.spin_max() <= opt.spin_max().zero()) {
return false;
return spin_result::advance;
}
auto tbegin = Clock::now();
while (true) {
if (f()) {
return true;
return spin_result::success;
}
auto const tnow = Clock::now();
if (tnow >= deadline) {
return false;
return spin_result::timeout;
}
// Backward time discontinuity in Clock? revise pre_block starting point
tbegin = std::min(tbegin, tnow);
if (tnow >= tbegin + opt.spin_max()) {
return false;
return spin_result::advance;
}
// The pause instruction is the polite way to spin, but it doesn't
......@@ -61,17 +67,17 @@ bool spin_pause_until(
}
template <typename Clock, typename Duration, typename F>
bool spin_yield_until(
spin_result spin_yield_until(
std::chrono::time_point<Clock, Duration> const& deadline,
F f) {
while (true) {
if (f()) {
return true;
return spin_result::success;
}
auto const max = std::chrono::time_point<Clock, Duration>::max();
if (deadline != max && Clock::now() >= deadline) {
return false;
return spin_result::timeout;
}
std::this_thread::yield();
......
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