void CRateLimiter::OnTimer(wxTimerEvent& event) { std::list<CRateLimiterObject*> objectsToUnwait; for (int i = 0; i < 2; i++) { m_tokenDebt[i] = 0; if (!m_objectList.size()) continue; int limit = m_pOptions->GetOptionVal(OPTION_SPEEDLIMIT_INBOUND + i) * 1024; if (!limit) { for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); iter++) { (*iter)->m_bytesAvailable[i] = -1; if ((*iter)->m_waiting[i]) m_wakeupList[i].push_back(*iter); } continue; } int tokens = limit * tickDelay / 1000; if (!tokens) tokens = 1; int maxTokens = tokens * GetBucketSize(); // Get amount of tokens for each object int tokensPerObject = tokens / m_objectList.size(); if (!tokensPerObject) tokensPerObject = 1; tokens = 0; // This list will hold all objects which didn't reach maxTokens std::list<CRateLimiterObject*> unsaturatedObjects; for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); iter++) { if ((*iter)->m_bytesAvailable[i] == -1) { wxASSERT(!(*iter)->m_waiting[i]); (*iter)->m_bytesAvailable[i] = tokensPerObject; unsaturatedObjects.push_back(*iter); } else { (*iter)->m_bytesAvailable[i] += tokensPerObject; if ((*iter)->m_bytesAvailable[i] > maxTokens) { tokens += (*iter)->m_bytesAvailable[i] - maxTokens; (*iter)->m_bytesAvailable[i] = maxTokens; } else unsaturatedObjects.push_back(*iter); if ((*iter)->m_waiting[i]) m_wakeupList[i].push_back(*iter); } } // If there are any left-over tokens (in case of objects with a rate below the limit) // assign to the unsaturated sources while (tokens && !unsaturatedObjects.empty()) { tokensPerObject = tokens / unsaturatedObjects.size(); if (!tokensPerObject) break; tokens = 0; std::list<CRateLimiterObject*> objects; objects.swap(unsaturatedObjects); for (std::list<CRateLimiterObject*>::iterator iter = objects.begin(); iter != objects.end(); iter++) { (*iter)->m_bytesAvailable[i] += tokensPerObject; if ((*iter)->m_bytesAvailable[i] > maxTokens) { tokens += (*iter)->m_bytesAvailable[i] - maxTokens; (*iter)->m_bytesAvailable[i] = maxTokens; } else unsaturatedObjects.push_back(*iter); } } } WakeupWaitingObjects(); if (m_objectList.empty()) m_timer.Stop(); }
void CRateLimiter::OnTimer(fz::timer_id) { fz::scoped_lock lock(sync_); int64_t const limits[2] = { GetLimit(inbound), GetLimit(outbound) }; for (int i = 0; i < 2; ++i) { m_tokenDebt[i] = 0; if (m_objectList.empty()) continue; if (limits[i] == 0) { for (auto iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) { (*iter)->m_bytesAvailable[i] = -1; if ((*iter)->m_waiting[i]) m_wakeupList[i].push_back(*iter); } continue; } int64_t tokens = (limits[i] * tickDelay) / 1000; int64_t maxTokens = tokens * GetBucketSize(); // Get amount of tokens for each object int64_t tokensPerObject = tokens / m_objectList.size(); if (tokensPerObject == 0) tokensPerObject = 1; tokens = 0; // This list will hold all objects which didn't reach maxTokens std::list<CRateLimiterObject*> unsaturatedObjects; for (auto iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) { if ((*iter)->m_bytesAvailable[i] == -1) { assert(!(*iter)->m_waiting[i]); (*iter)->m_bytesAvailable[i] = tokensPerObject; unsaturatedObjects.push_back(*iter); } else { (*iter)->m_bytesAvailable[i] += tokensPerObject; if ((*iter)->m_bytesAvailable[i] > maxTokens) { tokens += (*iter)->m_bytesAvailable[i] - maxTokens; (*iter)->m_bytesAvailable[i] = maxTokens; } else unsaturatedObjects.push_back(*iter); if ((*iter)->m_waiting[i]) m_wakeupList[i].push_back(*iter); } } // If there are any left-over tokens (in case of objects with a rate below the limit) // assign to the unsaturated sources while (tokens != 0 && !unsaturatedObjects.empty()) { tokensPerObject = tokens / unsaturatedObjects.size(); if (tokensPerObject == 0) break; tokens = 0; std::list<CRateLimiterObject*> objects; objects.swap(unsaturatedObjects); for (auto iter = objects.begin(); iter != objects.end(); ++iter) { (*iter)->m_bytesAvailable[i] += tokensPerObject; if ((*iter)->m_bytesAvailable[i] > maxTokens) { tokens += (*iter)->m_bytesAvailable[i] - maxTokens; (*iter)->m_bytesAvailable[i] = maxTokens; } else unsaturatedObjects.push_back(*iter); } } } WakeupWaitingObjects(lock); if (m_objectList.empty() || (limits[inbound] == 0 && limits[outbound] == 0)) { if (m_timer) { stop_timer(m_timer); m_timer = 0; } } }
void CRateLimiter::OnTimer(wxTimerEvent& event) { for (int i = 0; i < 2; ++i) { m_tokenDebt[i] = 0; if (m_objectList.empty()) continue; wxLongLong limit = GetLimit((enum rate_direction)i); if (limit == 0) { for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) { (*iter)->m_bytesAvailable[i] = -1; if ((*iter)->m_waiting[i]) m_wakeupList[i].push_back(*iter); } continue; } wxLongLong tokens = (limit * tickDelay) / 1000; wxLongLong maxTokens = tokens * GetBucketSize(); // Get amount of tokens for each object wxLongLong tokensPerObject = tokens / m_objectList.size(); if (tokensPerObject == 0) tokensPerObject = 1; tokens = 0; // This list will hold all objects which didn't reach maxTokens std::list<CRateLimiterObject*> unsaturatedObjects; for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) { if ((*iter)->m_bytesAvailable[i] == -1) { wxASSERT(!(*iter)->m_waiting[i]); (*iter)->m_bytesAvailable[i] = tokensPerObject; unsaturatedObjects.push_back(*iter); } else { (*iter)->m_bytesAvailable[i] += tokensPerObject; if ((*iter)->m_bytesAvailable[i] > maxTokens) { tokens += (*iter)->m_bytesAvailable[i] - maxTokens; (*iter)->m_bytesAvailable[i] = maxTokens; } else unsaturatedObjects.push_back(*iter); if ((*iter)->m_waiting[i]) m_wakeupList[i].push_back(*iter); } } // If there are any left-over tokens (in case of objects with a rate below the limit) // assign to the unsaturated sources while (tokens != 0 && !unsaturatedObjects.empty()) { tokensPerObject = tokens / unsaturatedObjects.size(); if (tokensPerObject == 0) break; tokens = 0; std::list<CRateLimiterObject*> objects; objects.swap(unsaturatedObjects); for (std::list<CRateLimiterObject*>::iterator iter = objects.begin(); iter != objects.end(); ++iter) { (*iter)->m_bytesAvailable[i] += tokensPerObject; if ((*iter)->m_bytesAvailable[i] > maxTokens) { tokens += (*iter)->m_bytesAvailable[i] - maxTokens; (*iter)->m_bytesAvailable[i] = maxTokens; } else unsaturatedObjects.push_back(*iter); } } } WakeupWaitingObjects(); if (m_objectList.empty()) m_timer.Stop(); }