bool LeakyBucket::ratelimit(int tokens) { // First remove tokens we leaked over time time_point tnow = now(); long ms = millisecondsBetween(lastUpdate, tnow); long drainTokens = (ms * tokensPerSec) / 1000; // Prevent constant starvation due to too many updates if (drainTokens > 0) { this->lastUpdate = tnow; this->currentTokens -= drainTokens; if (this->currentTokens < 0) { this->currentTokens = 0; } } // Then try to add tokens bool limit = this->currentTokens > ((static_cast<long>(maxTokens)) - tokens); // If the bucket is not overflowed, allow message and add tokens if (!limit) { this->currentTokens += tokens; } return limit; }
int asyncExecuteAlarmCallback (AsyncAlarmData *ad, long int *timeout) { if (ad) { Queue *alarms = ad->alarmQueue; if (alarms) { Element *element = processQueue(alarms, testInactiveAlarm, NULL); if (element) { AlarmEntry *alarm = getElementItem(element); TimeValue now; long int milliseconds; getMonotonicTime(&now); milliseconds = millisecondsBetween(&now, &alarm->time); if (milliseconds <= 0) { AsyncAlarmCallback *callback = alarm->callback; const AsyncAlarmCallbackParameters parameters = { .now = &now, .data = alarm->data }; logSymbol(LOG_CATEGORY(ASYNC_EVENTS), callback, "alarm starting"); alarm->active = 1; if (callback) callback(¶meters); alarm->active = 0; if (alarm->reschedule) { adjustTimeValue(&alarm->time, alarm->interval); getMonotonicTime(&now); if (compareTimeValues(&alarm->time, &now) < 0) alarm->time = now; requeueElement(element); } else { alarm->cancel = 1; } if (alarm->cancel) deleteElement(element); return 1; } if (milliseconds < *timeout) { *timeout = milliseconds; logSymbol(LOG_CATEGORY(ASYNC_EVENTS), alarm->callback, "next alarm: %ld", *timeout); } } } } return 0; }
bool HTTPTransaction::maybeDelayForRateLimit() { if (egressLimitBytesPerMs_ <= 0) { // No rate limiting return false; } if (numLimitedBytesEgressed_ == 0) { // If we haven't egressed any bytes yet, don't delay. return false; } int64_t limitedDurationMs = (int64_t) millisecondsBetween( getCurrentTime(), startRateLimit_ ).count(); // Algebra! Try to figure out the next time send where we'll // be allowed to send at least 1 full packet's worth. The // formula we're using is: // (bytesSoFar + packetSize) / (timeSoFar + delay) == targetRateLimit std::chrono::milliseconds requiredDelay( ( ((int64_t)numLimitedBytesEgressed_ + kApproximateMTU) - ((int64_t)egressLimitBytesPerMs_ * limitedDurationMs) ) / (int64_t)egressLimitBytesPerMs_ ); if (requiredDelay.count() <= 0) { // No delay required return false; } if (requiredDelay > kRateLimitMaxDelay) { // The delay should never be this long VLOG(4) << "ratelim: Required delay too long (" << requiredDelay.count() << "ms), ignoring"; return false; } // Delay required egressRateLimited_ = true; timeout_.scheduleTimeout(&rateLimitCallback_, requiredDelay); notifyTransportPendingEgress(); return true; }
static int awaitCursorMotion (RoutingData *routing, int direction, const CursorAxisEntry *axis) { int moved = 0; long int timeout = routing->timeSum / routing->timeCount; TimeValue start; int trgy = routing->cury; int trgx = routing->curx; routing->oldy = routing->cury; routing->oldx = routing->curx; axis->adjustCoordinate(&trgy, &trgx, direction); getMonotonicTime(&start); while (1) { long int time; TimeValue now; int oldy; int oldx; approximateDelay(ROUTING_INTERVAL); getMonotonicTime(&now); time = millisecondsBetween(&start, &now) + 1; { int row = routing->cury + routing->verticalDelta; int bestRow = row; int bestLength = 0; do { ScreenCharacter buffer[routing->screenColumns]; if (!readScreenRow(routing, buffer, row)) break; { int before = routing->curx; int after = before; while (buffer[before].text == routing->rowBuffer[before].text) if (--before < 0) break; while (buffer[after].text == routing->rowBuffer[after].text) if (++after >= routing->screenColumns) break; { int length = after - before - 1; if (length > bestLength) { bestRow = row; if ((bestLength = length) == routing->screenColumns) break; } } } row -= direction; } while ((row >= 0) && (row < routing->screenRows)); routing->verticalDelta = bestRow - routing->cury; } oldy = routing->cury; oldx = routing->curx; if (!getCurrentPosition(routing)) return 0; if ((routing->cury != oldy) || (routing->curx != oldx)) { logRouting("moved: [%d,%d] -> [%d,%d] (%dms)", oldx, oldy, routing->curx, routing->cury, time); if (!moved) { moved = 1; timeout = (time * 2) + 1; routing->timeSum += time * 8; routing->timeCount += 1; } if ((routing->cury == trgy) && (routing->curx == trgx)) break; if (ROUTING_INTERVAL) { start = now; } else { approximateDelay(1); getMonotonicTime(&start); } } else if (time > timeout) { if (!moved) logRouting("timed out: %ldms", timeout); break; } } return 1; }
long int millisecondsSince(const struct timeval *from) { struct timeval now; gettimeofday(&now, NULL); return millisecondsBetween(from, &now); }