isc_result_t isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) { isc_result_t result = ISC_R_SUCCESS; REQUIRE(rl != NULL); REQUIRE(interval != NULL); LOCK(&rl->lock); rl->interval = *interval; /* * If the timer is currently running, change its rate. */ if (rl->state == isc_ratelimiter_ratelimited) { result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL, &rl->interval, ISC_FALSE); } UNLOCK(&rl->lock); return (result); }
static void ratelimiter_tick(isc_task_t *task, isc_event_t *event) { isc_result_t result = ISC_R_SUCCESS; isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg; isc_event_t *p; isc_uint32_t pertic; UNUSED(task); isc_event_free(&event); pertic = rl->pertic; while (pertic != 0) { pertic--; LOCK(&rl->lock); p = ISC_LIST_HEAD(rl->pending); if (p != NULL) { /* * There is work to do. Let's do it after unlocking. */ ISC_LIST_UNLINK(rl->pending, p, ev_link); } else { /* * No work left to do. Stop the timer so that we don't * waste resources by having it fire periodically. */ result = isc_timer_reset(rl->timer, isc_timertype_inactive, NULL, NULL, ISC_FALSE); RUNTIME_CHECK(result == ISC_R_SUCCESS); rl->state = isc_ratelimiter_idle; pertic = 0; /* Force the loop to exit. */ } UNLOCK(&rl->lock); if (p != NULL) { isc_task_t *evtask = p->ev_sender; isc_task_send(evtask, &p); } INSIST(p == NULL); } }
isc_result_t isc_ratelimiter_stall(isc_ratelimiter_t *rl) { isc_result_t result = ISC_R_SUCCESS; LOCK(&rl->lock); switch (rl->state) { case isc_ratelimiter_shuttingdown: result = ISC_R_SHUTTINGDOWN; break; case isc_ratelimiter_ratelimited: result = isc_timer_reset(rl->timer, isc_timertype_inactive, NULL, NULL, ISC_FALSE); RUNTIME_CHECK(result == ISC_R_SUCCESS); case isc_ratelimiter_idle: case isc_ratelimiter_stalled: rl->state = isc_ratelimiter_stalled; break; } UNLOCK(&rl->lock); return (result); }
isc_result_t isc_ratelimiter_enqueue (isc_ratelimiter_t * rl, isc_task_t * task, isc_event_t ** eventp) { isc_result_t result = ISC_R_SUCCESS; isc_event_t *ev; REQUIRE (eventp != NULL && *eventp != NULL); REQUIRE (task != NULL); ev = *eventp; REQUIRE (ev->ev_sender == NULL); LOCK (&rl->lock); if (rl->state == isc_ratelimiter_ratelimited || rl->state == isc_ratelimiter_stalled) { isc_event_t *ev = *eventp; ev->ev_sender = task; ISC_LIST_APPEND (rl->pending, ev, ev_link); *eventp = NULL; } else if (rl->state == isc_ratelimiter_idle) { result = isc_timer_reset (rl->timer, isc_timertype_ticker, NULL, &rl->interval, ISC_FALSE); if (result == ISC_R_SUCCESS) { ev->ev_sender = task; rl->state = isc_ratelimiter_ratelimited; } } else { INSIST (rl->state == isc_ratelimiter_shuttingdown); result = ISC_R_SHUTTINGDOWN; } UNLOCK (&rl->lock); if (*eventp != NULL && result == ISC_R_SUCCESS) isc_task_send (task, eventp); return (result); }
isc_result_t dns_timer_setidle (isc_timer_t * timer, unsigned int maxtime, unsigned int idletime, isc_boolean_t purge) { isc_result_t result; isc_interval_t maxinterval, idleinterval; isc_time_t expires; /* Compute the time of expiry. */ isc_interval_set (&maxinterval, maxtime, 0); CHECK (isc_time_nowplusinterval (&expires, &maxinterval)); /* * Compute the idle interval, and add a spare nanosecond to * work around the silly limitation of the ISC timer interface * that you cannot specify an idle interval of zero. */ isc_interval_set (&idleinterval, idletime, 1); CHECK (isc_timer_reset (timer, isc_timertype_once, &expires, &idleinterval, purge)); failure: return (result); }
void isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) { isc_event_t *ev; isc_task_t *task; LOCK(&rl->lock); rl->state = isc_ratelimiter_shuttingdown; (void)isc_timer_reset(rl->timer, isc_timertype_inactive, NULL, NULL, ISC_FALSE); while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) { ISC_LIST_UNLINK(rl->pending, ev, ev_link); ev->ev_attributes |= ISC_EVENTATTR_CANCELED; task = ev->ev_sender; isc_task_send(task, &ev); } isc_timer_detach(&rl->timer); /* * Send an event to our task. The delivery of this event * indicates that no more timer events will be delivered. */ ev = &rl->shutdownevent; isc_task_send(rl->task, &ev); UNLOCK(&rl->lock); }
static void t4_te(isc_task_t *task, isc_event_t *event) { isc_result_t isc_result; isc_time_t now; isc_time_t base; isc_time_t ulim; isc_time_t llim; isc_time_t expires; isc_interval_t interval; ++Tx_eventcnt; t_info("tick %d\n", Tx_eventcnt); /* * Check expired time. */ isc_result = isc_time_now(&now); if (isc_result != ISC_R_SUCCESS) { t_info("isc_time_now failed %s\n", isc_result_totext(isc_result)); ++Tx_nprobs; } if (isc_result == ISC_R_SUCCESS) { interval.seconds = Tx_seconds; interval.nanoseconds = Tx_nanoseconds; isc_result = isc_time_add(&Tx_lasttime, &interval, &base); if (isc_result != ISC_R_SUCCESS) { t_info("isc_time_add failed %s\n", isc_result_totext(isc_result)); ++Tx_nprobs; } } if (isc_result == ISC_R_SUCCESS) { interval.seconds = Tx_FUDGE_SECONDS; interval.nanoseconds = Tx_FUDGE_NANOSECONDS; isc_result = isc_time_add(&base, &interval, &ulim); if (isc_result != ISC_R_SUCCESS) { t_info("isc_time_add failed %s\n", isc_result_totext(isc_result)); ++Tx_nprobs; } } if (isc_result == ISC_R_SUCCESS) { isc_result = isc_time_subtract(&base, &interval, &llim); if (isc_result != ISC_R_SUCCESS) { t_info("isc_time_subtract failed %s\n", isc_result_totext(isc_result)); ++Tx_nprobs; } } if (isc_result == ISC_R_SUCCESS) { if (isc_time_compare(&llim, &now) > 0) { t_info("timer range error: early by " "%lu microseconds\n", (unsigned long)isc_time_microdiff(&base, &now)); ++Tx_nfails; } else if (isc_time_compare(&ulim, &now) < 0) { t_info("timer range error: late by " "%lu microseconds\n", (unsigned long)isc_time_microdiff(&now, &base)); ++Tx_nfails; } Tx_lasttime = now; } if (Tx_eventcnt < 3) { if (event->ev_type != ISC_TIMEREVENT_TICK) { t_info("received event type %d, expected type %d\n", event->ev_type, ISC_TIMEREVENT_IDLE); ++Tx_nfails; } if (Tx_eventcnt == 2) { isc_interval_set(&interval, T4_SECONDS, T4_NANOSECONDS); isc_result = isc_time_nowplusinterval(&expires, &interval); if (isc_result == ISC_R_SUCCESS) { isc_interval_set(&interval, 0, 0); isc_result = isc_timer_reset(Tx_timer, isc_timertype_once, &expires, &interval, ISC_FALSE); if (isc_result != ISC_R_SUCCESS) { t_info("isc_timer_reset failed %s\n", isc_result_totext(isc_result)); ++Tx_nfails; } } else { t_info("isc_time_nowplusinterval failed %s\n", isc_result_totext(isc_result)); ++Tx_nprobs; } } } else { if (event->ev_type != ISC_TIMEREVENT_LIFE) { t_info("received event type %d, expected type %d\n", event->ev_type, ISC_TIMEREVENT_IDLE); ++Tx_nfails; } isc_timer_detach(&Tx_timer); isc_task_shutdown(task); } isc_event_free(&event); }