in cpp/logger/lfrb/TurnSequencer.h [116:198]
TryWaitResult tryWaitForTurn(
const uint32_t turn,
Atom<uint32_t>& spinCutoff,
const bool updateSpinCutoff,
const std::chrono::time_point<Clock, Duration>* absTime =
nullptr) noexcept {
uint32_t prevThresh = spinCutoff.load(std::memory_order_relaxed);
const uint32_t effectiveSpinCutoff =
updateSpinCutoff || prevThresh == 0 ? kMaxSpins : prevThresh;
uint32_t tries;
const uint32_t sturn = turn << kTurnShift;
for (tries = 0;; ++tries) {
uint32_t state = state_.load(std::memory_order_acquire);
uint32_t current_sturn = decodeCurrentSturn(state);
if (current_sturn == sturn) {
break;
}
// wrap-safe version of (current_sturn >= sturn)
if (sturn - current_sturn >= std::numeric_limits<uint32_t>::max() / 2) {
// turn is in the past
return TryWaitResult::PAST;
}
// the first effectSpinCutoff tries are spins, after that we will
// record ourself as a waiter and block with futexWait
if (tries < effectiveSpinCutoff) {
continue;
}
uint32_t current_max_waiter_delta = decodeMaxWaitersDelta(state);
uint32_t our_waiter_delta = (sturn - current_sturn) >> kTurnShift;
uint32_t new_state;
if (our_waiter_delta <= current_max_waiter_delta) {
// state already records us as waiters, probably because this
// isn't our first time around this loop
new_state = state;
} else {
new_state = encode(current_sturn, our_waiter_delta);
if (state != new_state &&
!state_.compare_exchange_strong(state, new_state)) {
continue;
}
}
if (absTime) {
auto futexResult =
state_.futexWaitUntil(new_state, *absTime, futexChannel(turn));
if (futexResult == FutexResult::TIMEDOUT) {
return TryWaitResult::TIMEDOUT;
}
} else {
state_.futexWait(new_state, futexChannel(turn));
}
}
if (updateSpinCutoff || prevThresh == 0) {
// if we hit kMaxSpins then spinning was pointless, so the right
// spinCutoff is kMinSpins
uint32_t target;
if (tries >= kMaxSpins) {
target = kMinSpins;
} else {
// to account for variations, we allow ourself to spin 2*N when
// we think that N is actually required in order to succeed
target = std::min<uint32_t>(
kMaxSpins, std::max<uint32_t>(kMinSpins, tries * 2));
}
if (prevThresh == 0) {
// bootstrap
spinCutoff.store(target);
} else {
// try once, keep moving if CAS fails. Exponential moving average
// with alpha of 7/8
// Be careful that the quantity we add to prevThresh is signed.
spinCutoff.compare_exchange_weak(
prevThresh, prevThresh + int(target - prevThresh) / 8);
}
}
return TryWaitResult::SUCCESS;
}