/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2014-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef FOLLY_DETAIL_MEMORYIDLER_H
-#define FOLLY_DETAIL_MEMORYIDLER_H
+#pragma once
#include <atomic>
#include <chrono>
-#include <folly/AtomicStruct.h>
-#include <folly/Hash.h>
-#include <folly/Traits.h>
-#include "Futex.h"
-namespace folly {
-
-// gcc 4.7 doesn't do std::is_trivial correctly, override so we can use
-// AtomicStruct<duration>
-template<>
-struct IsTriviallyCopyable<std::chrono::steady_clock::duration>
- : std::true_type {};
-
-}
+#include <folly/detail/Futex.h>
+#include <folly/hash/Hash.h>
+#include <folly/synchronization/AtomicStruct.h>
+#include <folly/system/ThreadId.h>
namespace folly { namespace detail {
/// avoid synchronizing their flushes.
static AtomicStruct<std::chrono::steady_clock::duration> defaultIdleTimeout;
+ /// Selects a timeout pseudo-randomly chosen to be between
+ /// idleTimeout and idleTimeout * (1 + timeoutVariationFraction), to
+ /// smooth out the behavior in a bursty system
+ template <typename Clock = std::chrono::steady_clock>
+ static typename Clock::duration getVariationTimeout(
+ typename Clock::duration idleTimeout
+ = defaultIdleTimeout.load(std::memory_order_acquire),
+ float timeoutVariationFrac = 0.5) {
+ if (idleTimeout.count() > 0 && timeoutVariationFrac > 0) {
+ // hash the pthread_t and the time to get the adjustment.
+ // Standard hash func isn't very good, so bit mix the result
+ auto pr = std::make_pair(getCurrentThreadID(),
+ Clock::now().time_since_epoch().count());
+ std::hash<decltype(pr)> hash_fn;
+ uint64_t h = folly::hash::twang_mix64(hash_fn(pr));
+
+ // multiplying the duration by a floating point doesn't work, grr..
+ auto extraFrac =
+ timeoutVariationFrac / std::numeric_limits<uint64_t>::max() * h;
+ auto tics = uint64_t(idleTimeout.count() * (1 + extraFrac));
+ idleTimeout = typename Clock::duration(tics);
+ }
+
+ return idleTimeout;
+ }
/// Equivalent to fut.futexWait(expected, waitMask), but calls
/// flushLocalMallocCaches() and unmapUnusedStack(stackToRetain)
/// (1 + timeoutVariationFraction), to smooth out the behavior in a
/// system with bursty requests. The default is to wait up to 50%
/// extra, so on average 25% extra
- template <template <typename> class Atom,
- typename Clock = std::chrono::steady_clock>
- static bool futexWait(
+ template <
+ template <typename> class Atom,
+ typename Clock = std::chrono::steady_clock>
+ static FutexResult futexWait(
Futex<Atom>& fut,
uint32_t expected,
uint32_t waitMask = -1,
- typename Clock::duration idleTimeout
- = defaultIdleTimeout.load(std::memory_order_acquire),
+ typename Clock::duration idleTimeout =
+ defaultIdleTimeout.load(std::memory_order_acquire),
size_t stackToRetain = kDefaultStackToRetain,
float timeoutVariationFrac = 0.5) {
-
if (idleTimeout == Clock::duration::max()) {
// no need to use futexWaitUntil if no timeout is possible
return fut.futexWait(expected, waitMask);
}
+ idleTimeout = getVariationTimeout(idleTimeout, timeoutVariationFrac);
if (idleTimeout.count() > 0) {
- auto begin = Clock::now();
-
- if (timeoutVariationFrac > 0) {
- // hash the pthread_t and the time to get the adjustment.
- // Standard hash func isn't very good, so bit mix the result
- auto pr = std::make_pair(pthread_self(),
- begin.time_since_epoch().count());
- std::hash<decltype(pr)> hash_fn;
- uint64_t h = folly::hash::twang_mix64(hash_fn(pr));
-
- // multiplying the duration by a floating point doesn't work, grr..
- auto extraFrac =
- timeoutVariationFrac / std::numeric_limits<uint64_t>::max() * h;
- uint64_t tics = idleTimeout.count() * (1 + extraFrac);
- idleTimeout = typename Clock::duration(tics);
- }
-
while (true) {
- auto rv = fut.futexWaitUntil(expected, begin + idleTimeout, waitMask);
+ auto rv = fut.futexWaitUntil(
+ expected, Clock::now() + idleTimeout, waitMask);
if (rv == FutexResult::TIMEDOUT) {
// timeout is over
break;
// finished before timeout hit, no flush
assert(rv == FutexResult::VALUE_CHANGED || rv == FutexResult::AWOKEN ||
rv == FutexResult::INTERRUPTED);
- return rv == FutexResult::AWOKEN;
+ return rv;
}
}
}
};
-}} // namespace folly::detail
-
-#endif
+} // namespace detail
+} // namespace folly