mirror of
https://github.com/schoebel/mars
synced 2024-12-21 22:30:08 +00:00
infra: fix limiter underflow
Credits to Daniel Hermann for revealing this bug.
This commit is contained in:
parent
5eae58a3a4
commit
dae1218c50
@ -16,8 +16,17 @@ int mars_limit(struct mars_limiter *lim, int amount)
|
||||
* down to the root of the hierarchy tree.
|
||||
*/
|
||||
while (lim != NULL) {
|
||||
if (likely(lim->lim_stamp)) {
|
||||
long long elapsed = now - lim->lim_stamp;
|
||||
long long elapsed = now - lim->lim_stamp;
|
||||
/* Sometimes, raw CPU clocks may do weired things...
|
||||
*/
|
||||
if (unlikely(elapsed <= 0))
|
||||
elapsed = 1;
|
||||
|
||||
/* Only use incremental accumulation at repeated calls, but
|
||||
* never after longer pauses.
|
||||
*/
|
||||
if (likely(lim->lim_stamp && elapsed < LIMITER_TIME_RESOLUTION * 8)) {
|
||||
long long rate_raw;
|
||||
int rate;
|
||||
|
||||
/* Races are possible, but taken into account.
|
||||
@ -26,7 +35,11 @@ int mars_limit(struct mars_limiter *lim, int amount)
|
||||
if (likely(amount > 0))
|
||||
lim->lim_accu += amount;
|
||||
|
||||
rate = (long long)lim->lim_accu * LIMITER_TIME_RESOLUTION / elapsed;
|
||||
rate_raw = lim->lim_accu * LIMITER_TIME_RESOLUTION / elapsed;
|
||||
rate = rate_raw;
|
||||
if (unlikely(rate_raw > INT_MAX)) {
|
||||
rate = INT_MAX;
|
||||
}
|
||||
lim->lim_rate = rate;
|
||||
|
||||
// limit exceeded?
|
||||
@ -40,8 +53,9 @@ int mars_limit(struct mars_limiter *lim, int amount)
|
||||
elapsed -= LIMITER_TIME_RESOLUTION * 2;
|
||||
if (elapsed > LIMITER_TIME_RESOLUTION) {
|
||||
lim->lim_stamp += elapsed;
|
||||
if (lim->lim_accu > 0) {
|
||||
lim->lim_accu -= (long long)lim->lim_max_rate * elapsed / LIMITER_TIME_RESOLUTION;
|
||||
lim->lim_accu -= (unsigned long long)lim->lim_rate * (unsigned long long)elapsed / LIMITER_TIME_RESOLUTION;
|
||||
if (lim->lim_accu < 0) {
|
||||
lim->lim_accu = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -17,7 +17,7 @@ struct mars_limiter {
|
||||
int lim_rate;
|
||||
long long lim_stamp;
|
||||
/* internal */
|
||||
int lim_accu;
|
||||
long long lim_accu;
|
||||
};
|
||||
|
||||
extern int mars_limit(struct mars_limiter *lim, int amount);
|
||||
|
Loading…
Reference in New Issue
Block a user