summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bufferevent_ratelim.c65
1 files changed, 45 insertions, 20 deletions
diff --git a/bufferevent_ratelim.c b/bufferevent_ratelim.c
index 814fcf79..a70cd8db 100644
--- a/bufferevent_ratelim.c
+++ b/bufferevent_ratelim.c
@@ -543,15 +543,19 @@ bufferevent_set_rate_limit(struct bufferevent *bev,
struct bufferevent_rate_limit *rlim;
struct timeval now;
ev_uint32_t tick;
+ int reinit = 0, suspended = 0;
/* XXX reference-count cfg */
BEV_LOCK(bev);
if (cfg == NULL) {
if (bevp->rate_limiting) {
- bevp->rate_limiting->cfg = NULL;
+ rlim = bevp->rate_limiting;
+ rlim->cfg = NULL;
bufferevent_unsuspend_read(bev, BEV_SUSPEND_BW);
bufferevent_unsuspend_write(bev, BEV_SUSPEND_BW);
+ if (event_initialized(&rlim->refill_bucket_event))
+ event_del(&rlim->refill_bucket_event);
}
r = 0;
goto done;
@@ -561,29 +565,48 @@ bufferevent_set_rate_limit(struct bufferevent *bev,
tick = ev_token_bucket_get_tick(&now, cfg);
if (bevp->rate_limiting && bevp->rate_limiting->cfg == cfg) {
- ;
- } else if (bevp->rate_limiting) {
- bevp->rate_limiting->cfg = cfg;
- ev_token_bucket_init(&bevp->rate_limiting->limit, cfg, tick, 1);
- if (bevp->rate_limiting->limit.read_limit > 0)
- bufferevent_unsuspend_read(bev, BEV_SUSPEND_BW);
- else
- bufferevent_suspend_read(bev, BEV_SUSPEND_BW);
- if (bevp->rate_limiting->limit.write_limit > 0)
- bufferevent_unsuspend_write(bev, BEV_SUSPEND_BW);
- else
- bufferevent_suspend_write(bev, BEV_SUSPEND_BW);
- } else {
+ /* no-op */
+ r = 0;
+ goto done;
+ }
+ if (bevp->rate_limiting == NULL) {
rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
if (!rlim)
goto done;
- rlim->cfg = cfg;
- ev_token_bucket_init(&rlim->limit, cfg, tick, 0);
- evtimer_assign(&rlim->refill_bucket_event, bev->ev_base,
- _bev_refill_callback, bevp);
bevp->rate_limiting = rlim;
+ } else {
+ rlim = bevp->rate_limiting;
+ }
+ reinit = rlim->cfg != NULL;
+
+ rlim->cfg = cfg;
+ ev_token_bucket_init(&rlim->limit, cfg, tick, reinit);
+
+ if (reinit) {
+ EVUTIL_ASSERT(event_initialized(&rlim->refill_bucket_event));
+ event_del(&rlim->refill_bucket_event);
}
+ evtimer_assign(&rlim->refill_bucket_event, bev->ev_base,
+ _bev_refill_callback, bevp);
+
+ if (rlim->limit.read_limit > 0) {
+ bufferevent_unsuspend_read(bev, BEV_SUSPEND_BW);
+ } else {
+ bufferevent_suspend_read(bev, BEV_SUSPEND_BW);
+ suspended=1;
+ }
+ if (rlim->limit.write_limit > 0) {
+ bufferevent_unsuspend_write(bev, BEV_SUSPEND_BW);
+ } else {
+ bufferevent_suspend_write(bev, BEV_SUSPEND_BW);
+ suspended = 1;
+ }
+
+ if (suspended)
+ event_add(&rlim->refill_bucket_event, &cfg->tick_timeout);
+
r = 0;
+
done:
BEV_UNLOCK(bev);
return r;
@@ -856,7 +879,8 @@ bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr)
&bevp->rate_limiting->cfg->tick_timeout) < 0)
r = -1;
} else if (old_limit <= 0 && new_limit > 0) {
- event_del(&bevp->rate_limiting->refill_bucket_event);
+ if (!(bevp->write_suspended & BEV_SUSPEND_BW))
+ event_del(&bevp->rate_limiting->refill_bucket_event);
bufferevent_unsuspend_read(bev, BEV_SUSPEND_BW);
}
@@ -884,7 +908,8 @@ bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr)
&bevp->rate_limiting->cfg->tick_timeout) < 0)
r = -1;
} else if (old_limit <= 0 && new_limit > 0) {
- event_del(&bevp->rate_limiting->refill_bucket_event);
+ if (!(bevp->read_suspended & BEV_SUSPEND_BW))
+ event_del(&bevp->rate_limiting->refill_bucket_event);
bufferevent_unsuspend_write(bev, BEV_SUSPEND_BW);
}