bool Throttle::requestPermission(int numActions, const bsls::TimeInterval& now) { #if defined(BSLS_ASSERT_IS_ACTIVE) BSLS_ASSERT(0 < numActions); BSLS_ASSERT(now.seconds() <= k_MAX_SECONDS); BSLS_ASSERT(now.seconds() >= k_MIN_SECONDS); const Int64 sns = k_BILLION * now.seconds(); // Seconds in NanoSeconds if (0 <= sns) { BSLS_ASSERT(LLONG_MAX - sns > now.nanoseconds()); } else { BSLS_ASSERT(LLONG_MIN - sns < now.nanoseconds()); } #endif if (d_maxSimultaneousActions < numActions) { BSLS_ASSERT(0 == d_maxSimultaneousActions); // It is best to deal with the 'allow none' case here. We have to do // the above two conditions just for asserts on our way into the // method, and if we don't handle the // 'd_maxSimultaneousActions < numActions' case here we risk undefined // behavior due to signed arithmetic overflow later on. return false; // RETURN } // Testing for 'k_ALLOW_ALL' here prevents undefined behavior later in the // function due to overflowing signed arithmetic. if (k_ALLOW_ALL == d_nanosecondsPerAction) { return true; // RETURN } const Int64 currentTime = now.totalNanoseconds(); const Int64 requiredTime = numActions * d_nanosecondsPerAction; const Int64 lagTime = d_nanosecondsPerTotalReset - requiredTime; Int64 prevLeakTime = AtomicOps::getInt64Acquire(&d_prevLeakTime); while (true) { const Int64 timeDiff = currentTime - prevLeakTime; if (timeDiff < requiredTime) { return false; // RETURN } const Int64 nextLeakTime = d_nanosecondsPerTotalReset <= timeDiff ? currentTime - lagTime : prevLeakTime + requiredTime; const Int64 swappedLeakTime = AtomicOps::testAndSwapInt64AcqRel( &d_prevLeakTime, prevLeakTime, nextLeakTime); if (swappedLeakTime == prevLeakTime) { return true; // RETURN } prevLeakTime = swappedLeakTime; } }
bool Throttle::requestPermission(const bsls::TimeInterval& now) { #if defined(BSLS_ASSERT_IS_ACTIVE) BSLS_ASSERT(now.seconds() <= k_MAX_SECONDS); BSLS_ASSERT(now.seconds() >= k_MIN_SECONDS); const Int64 sns = k_BILLION * now.seconds(); // Seconds in NanoSeconds if (0 <= sns) { BSLS_ASSERT(LLONG_MAX - sns > now.nanoseconds()); } else { BSLS_ASSERT(LLONG_MIN - sns < now.nanoseconds()); } #endif // Special casing 'allow all' here prevents undefined behavior later in // the function due to overflowing signed arithmetic. if (k_ALLOW_ALL == d_nanosecondsPerAction) { return true; // RETURN } const Int64 currentTime = now.totalNanoseconds(); Int64 prevLeakTime = AtomicOps::getInt64Acquire(&d_prevLeakTime); while (true) { const Int64 timeDiff = currentTime - prevLeakTime; if (timeDiff < d_nanosecondsPerAction) { return false; // RETURN } const Int64 nextLeakTime = d_nanosecondsPerTotalReset <= timeDiff ? currentTime - d_nanosecondsPerTotalReset + d_nanosecondsPerAction : prevLeakTime + d_nanosecondsPerAction; const Int64 swappedLeakTime = AtomicOps::testAndSwapInt64AcqRel( &d_prevLeakTime, prevLeakTime, nextLeakTime); if (swappedLeakTime == prevLeakTime) { return true; // RETURN } prevLeakTime = swappedLeakTime; } }