Esempio n. 1
0
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;
    }
}
Esempio n. 2
0
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;
    }
}