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