/* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation * Copyright © 2013-2015 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "util-ratelimit.h" #include "util-time.h" void ratelimit_init(struct ratelimit *r, uint64_t ival_us, unsigned int burst) { r->interval = ival_us; r->begin = 0; r->burst = burst; r->num = 0; } /* * Perform rate-limit test. Returns RATELIMIT_PASS if the rate-limited action * is still allowed, RATELIMIT_THRESHOLD if the limit has been reached with * this call, and RATELIMIT_EXCEEDED if you're beyond the threshold. * It's safe to treat the return-value as boolean, if you're not interested in * the exact state. It evaluates to "true" if the threshold hasn't been * exceeded, yet. * * The ratelimit object must be initialized via ratelimit_init(). * * Modelled after Linux' lib/ratelimit.c by Dave Young * , which is licensed GPLv2. */ enum ratelimit_state ratelimit_test(struct ratelimit *r) { struct timespec ts; uint64_t utime; if (r->interval <= 0 || r->burst <= 0) return RATELIMIT_PASS; clock_gettime(CLOCK_MONOTONIC, &ts); utime = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); if (r->begin <= 0 || r->begin + r->interval < utime) { /* reset counter */ r->begin = utime; r->num = 1; return RATELIMIT_PASS; } if (r->num < r->burst) { /* continue burst */ return (++r->num == r->burst) ? RATELIMIT_THRESHOLD : RATELIMIT_PASS; } return RATELIMIT_EXCEEDED; }