Merge branch '3202-cleanup-isc_timer-API' into 'main'

Refactor and simplify isc_timer API

See merge request isc-projects/bind9!5966
This commit is contained in:
Ondřej Surý 2022-03-14 21:13:24 +00:00
commit 13b20ef411
20 changed files with 263 additions and 618 deletions

View file

@ -1,3 +1,7 @@
5829. [func] Refactor and simplify isc_timer API in preparation
for further refactoring on top of network manager
loops. [GL #3202]
5828. [bug] Replace single TCP write timer with per-TCP write
timers. [GL #3200]

View file

@ -278,9 +278,6 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
command_compare(command, NAMED_COMMAND_UNFREEZE))
{
result = named_server_freeze(named_g_server, false, lex, text);
} else if (command_compare(command, NAMED_COMMAND_TIMERPOKE)) {
isc_timermgr_poke(named_g_timermgr);
result = ISC_R_SUCCESS;
} else if (command_compare(command, NAMED_COMMAND_TRACE)) {
result = named_server_setdebuglevel(named_g_server, lex);
} else if (command_compare(command, NAMED_COMMAND_TSIGDELETE)) {

View file

@ -48,7 +48,6 @@
#define NAMED_COMMAND_FREEZE "freeze"
#define NAMED_COMMAND_UNFREEZE "unfreeze"
#define NAMED_COMMAND_THAW "thaw"
#define NAMED_COMMAND_TIMERPOKE "timerpoke"
#define NAMED_COMMAND_RECURSING "recursing"
#define NAMED_COMMAND_NULL "null"
#define NAMED_COMMAND_NOTIFY "notify"

View file

@ -9059,13 +9059,11 @@ load_configuration(const char *filename, named_server_t *server,
interface_interval = cfg_obj_asduration(obj);
if (interface_interval == 0) {
CHECK(isc_timer_reset(server->interface_timer,
isc_timertype_inactive, NULL, NULL,
true));
isc_timertype_inactive, NULL, true));
} else if (server->interface_interval != interface_interval) {
isc_interval_set(&interval, interface_interval, 0);
CHECK(isc_timer_reset(server->interface_timer,
isc_timertype_ticker, NULL, &interval,
false));
isc_timertype_ticker, &interval, false));
}
server->interface_interval = interface_interval;
@ -9086,22 +9084,20 @@ load_configuration(const char *filename, named_server_t *server,
heartbeat_interval = cfg_obj_asuint32(obj) * 60;
if (heartbeat_interval == 0) {
CHECK(isc_timer_reset(server->heartbeat_timer,
isc_timertype_inactive, NULL, NULL,
true));
isc_timertype_inactive, NULL, true));
} else if (server->heartbeat_interval != heartbeat_interval) {
isc_interval_set(&interval, heartbeat_interval, 0);
CHECK(isc_timer_reset(server->heartbeat_timer,
isc_timertype_ticker, NULL, &interval,
false));
isc_timertype_ticker, &interval, false));
}
server->heartbeat_interval = heartbeat_interval;
isc_interval_set(&interval, 1200, 0);
CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker,
&interval, false));
isc_interval_set(&interval, named_g_tat_interval, 0);
CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker,
&interval, false));
/*
@ -9942,27 +9938,17 @@ run_server(isc_task_t *task, isc_event_t *event) {
true, &server->interfacemgr),
"creating interface manager");
CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
NULL, NULL, server->task,
interface_timer_tick, server,
&server->interface_timer),
"creating interface timer");
isc_timer_create(named_g_timermgr, server->task, interface_timer_tick,
server, &server->interface_timer);
CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
NULL, NULL, server->task,
heartbeat_timer_tick, server,
&server->heartbeat_timer),
"creating heartbeat timer");
isc_timer_create(named_g_timermgr, server->task, heartbeat_timer_tick,
server, &server->heartbeat_timer);
CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
NULL, NULL, server->task, tat_timer_tick,
server, &server->tat_timer),
"creating trust anchor telemetry timer");
isc_timer_create(named_g_timermgr, server->task, tat_timer_tick, server,
&server->tat_timer);
CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
NULL, NULL, server->task, pps_timer_tick,
server, &server->pps_timer),
"creating pps timer");
isc_timer_create(named_g_timermgr, server->task, pps_timer_tick, server,
&server->pps_timer);
CHECKFATAL(
cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),

View file

@ -0,0 +1,6 @@
@@
expression E1, E2, E3, E4;
@@
- isc_timer_reset(E1, E2, NULL, E3, E4)
+ isc_timer_reset(E1, E2, E3, E4)

View file

@ -1400,8 +1400,9 @@ be triggered at that time.
* 'arg' as its argument in task 'task'.
*/
isc_timer_t *timer = NULL;
result = isc_timer_create(timermgr, isc_timertype_once, NULL,
interval, task, timeout, arg, &timer);
result = isc_timer_create(timermgr, task, timeout, arg, &timer);
result = isc_timer_reset(timermgr, isc_timertype_once, NULL,
interval, false);
An event can also be explicitly triggered via `isc_task_send()`.

View file

@ -617,7 +617,6 @@ dns_catz_catzs_set_view(dns_catz_zones_t *catzs, dns_view_t *view) {
isc_result_t
dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
const dns_name_t *name) {
isc_result_t result;
dns_catz_zone_t *new_zone;
REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
@ -634,13 +633,9 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
isc_ht_init(&new_zone->entries, catzs->mctx, 4);
new_zone->updatetimer = NULL;
result = isc_timer_create(catzs->timermgr, isc_timertype_inactive, NULL,
NULL, catzs->updater,
dns_catz_update_taskaction, new_zone,
&new_zone->updatetimer);
if (result != ISC_R_SUCCESS) {
goto cleanup_ht;
}
isc_timer_create(catzs->timermgr, catzs->updater,
dns_catz_update_taskaction, new_zone,
&new_zone->updatetimer);
isc_time_settoepoch(&new_zone->lastupdated);
new_zone->updatepending = false;
@ -658,13 +653,6 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
*zonep = new_zone;
return (ISC_R_SUCCESS);
cleanup_ht:
isc_ht_destroy(&new_zone->entries);
dns_name_free(&new_zone->name, catzs->mctx);
isc_mem_put(catzs->mctx, new_zone, sizeof(*new_zone));
return (result);
}
isc_result_t
@ -1684,7 +1672,7 @@ dns_catz_update_taskaction(isc_task_t *task, isc_event_t *event) {
zone->updatepending = false;
dns_catz_update_from_db(zone->db, zone->catzs);
result = isc_timer_reset(zone->updatetimer, isc_timertype_inactive,
NULL, NULL, true);
NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_event_free(&event);
result = isc_time_now(&zone->lastupdated);
@ -1745,8 +1733,8 @@ dns_catz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
0);
dns_db_currentversion(db, &zone->dbversion);
result = isc_timer_reset(zone->updatetimer,
isc_timertype_once, NULL,
&interval, true);
isc_timertype_once, &interval,
true);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}

View file

@ -74,9 +74,8 @@ nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
isc_refcount_destroy(&nta->refcount);
nta->magic = 0;
if (nta->timer != NULL) {
(void)isc_timer_reset(nta->timer,
isc_timertype_inactive, NULL,
NULL, true);
(void)isc_timer_reset(
nta->timer, isc_timertype_inactive, NULL, true);
isc_timer_detach(&nta->timer);
}
if (dns_rdataset_isassociated(&nta->rdataset)) {
@ -233,7 +232,7 @@ fetch_done(isc_task_t *task, isc_event_t *event) {
*/
if (nta->timer != NULL && nta->expiry - now < view->nta_recheck) {
(void)isc_timer_reset(nta->timer, isc_timertype_inactive, NULL,
NULL, true);
true);
}
nta_detach(view->mctx, &nta);
dns_view_weakdetach(&view);
@ -289,10 +288,14 @@ settimer(dns_ntatable_t *ntatable, dns_nta_t *nta, uint32_t lifetime) {
return (ISC_R_SUCCESS);
}
isc_timer_create(ntatable->timermgr, ntatable->task, checkbogus, nta,
&nta->timer);
isc_interval_set(&interval, view->nta_recheck, 0);
result = isc_timer_create(ntatable->timermgr, isc_timertype_ticker,
NULL, &interval, ntatable->task, checkbogus,
nta, &nta->timer);
result = isc_timer_reset(nta->timer, isc_timertype_ticker, &interval,
false);
if (result != ISC_R_SUCCESS) {
isc_timer_detach(&nta->timer);
}
return (result);
}
@ -476,9 +479,8 @@ again:
"deleting expired NTA at %s", nb);
if (nta->timer != NULL) {
(void)isc_timer_reset(nta->timer,
isc_timertype_inactive, NULL,
NULL, true);
(void)isc_timer_reset(
nta->timer, isc_timertype_inactive, NULL, true);
isc_timer_detach(&nta->timer);
}
@ -689,7 +691,7 @@ dns_ntatable_shutdown(dns_ntatable_t *ntatable) {
if (nta->timer != NULL) {
(void)isc_timer_reset(nta->timer,
isc_timertype_inactive,
NULL, NULL, true);
NULL, true);
}
}
result = dns_rbtnodechain_next(&chain, NULL, NULL);

View file

@ -337,7 +337,6 @@ struct fetchctx {
isc_time_t expires;
isc_time_t expires_try_stale;
isc_time_t next_timeout;
isc_time_t final;
isc_interval_t interval;
dns_message_t *qmessage;
ISC_LIST(resquery_t) queries;
@ -1255,8 +1254,22 @@ update_edns_stats(resquery_t *query) {
*/
static inline isc_result_t
fctx_starttimer(fetchctx_t *fctx) {
return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->final,
NULL, true));
isc_interval_t interval;
isc_time_t now;
isc_time_t expires;
isc_interval_set(&interval, 2, 0);
isc_time_add(&fctx->expires, &interval, &expires);
isc_time_now(&now);
if (isc_time_compare(&expires, &now) <= 0) {
isc_interval_set(&interval, 0, 1);
} else {
isc_time_subtract(&expires, &now, &interval);
}
return (isc_timer_reset(fctx->timer, isc_timertype_once, &interval,
true));
}
static inline void
@ -1270,7 +1283,7 @@ fctx_stoptimer(fetchctx_t *fctx) {
* cannot fail in that case.
*/
result = isc_timer_reset(fctx->timer, isc_timertype_inactive, NULL,
NULL, true);
true);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_reset(): %s",
isc_result_totext(result));
@ -1728,7 +1741,7 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) {
}
isc_interval_set(&i, 20 * 60, 0);
result = isc_timer_reset(fctx->res->spillattimer,
isc_timertype_ticker, NULL, &i,
isc_timertype_ticker, &i,
true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
@ -4533,6 +4546,13 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
UNLOCK(&res->buckets[bucketnum].lock);
/*
* As a backstop, we also set a timer to stop the fetch
* if in-band netmgr timeouts don't work. It will fire two
* seconds after the fetch should have finished. (This
* should be enough of a gap to avoid the timer firing
* while a response is being processed normally.)
*/
result = fctx_starttimer(fctx);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
@ -4836,36 +4856,13 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
goto cleanup_qmessage;
}
/*
* As a backstop, we also set a timer to stop the fetch
* if in-band netmgr timeouts don't work. It will fire two
* seconds after the fetch should have finished. (This
* should be enough of a gap to avoid the timer firing
* while a response is being processed normally.)
*/
isc_interval_set(&interval, 2, 0);
iresult = isc_time_add(&fctx->expires, &interval, &fctx->final);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_time_add: %s",
isc_result_totext(iresult));
result = ISC_R_UNEXPECTED;
goto cleanup_qmessage;
}
/*
* Create an inactive timer to enforce maximum query
* lifetime. It will be made active when the fetch is
* started.
*/
iresult = isc_timer_create(res->timermgr, isc_timertype_inactive, NULL,
NULL, res->buckets[bucketnum].task,
fctx_expired, fctx, &fctx->timer);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_create: %s",
isc_result_totext(iresult));
result = ISC_R_UNEXPECTED;
goto cleanup_qmessage;
}
isc_timer_create(res->timermgr, res->buckets[bucketnum].task,
fctx_expired, fctx, &fctx->timer);
/*
* Default retry interval initialization. We set the interval
@ -10029,8 +10026,7 @@ spillattimer_countdown(isc_task_t *task, isc_event_t *event) {
}
if (res->spillat <= res->spillatmin) {
result = isc_timer_reset(res->spillattimer,
isc_timertype_inactive, NULL, NULL,
true);
isc_timertype_inactive, NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
count = res->spillat;
@ -10167,13 +10163,9 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
}
isc_task_setname(task, "resolver_task", NULL);
result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
task, spillattimer_countdown, res,
&res->spillattimer);
isc_timer_create(timermgr, task, spillattimer_countdown, res,
&res->spillattimer);
isc_task_detach(&task);
if (result != ISC_R_SUCCESS) {
goto cleanup_primelock;
}
res->magic = RES_MAGIC;
@ -10405,8 +10397,7 @@ dns_resolver_shutdown(dns_resolver_t *res) {
send_shutdown_events(res);
}
result = isc_timer_reset(res->spillattimer,
isc_timertype_inactive, NULL, NULL,
true);
isc_timertype_inactive, NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
UNLOCK(&res->lock);

View file

@ -1514,7 +1514,6 @@ cleanup_rbt:
isc_result_t
dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) {
dns_rpz_zone_t *zone;
isc_result_t result;
REQUIRE(rpzp != NULL && *rpzp == NULL);
REQUIRE(rpzs != NULL);
@ -1527,13 +1526,8 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) {
memset(zone, 0, sizeof(*zone));
isc_refcount_init(&zone->refs, 1);
result = isc_timer_create(rpzs->timermgr, isc_timertype_inactive, NULL,
NULL, rpzs->updater,
dns_rpz_update_taskaction, zone,
&zone->updatetimer);
if (result != ISC_R_SUCCESS) {
goto cleanup_timer;
}
isc_timer_create(rpzs->timermgr, rpzs->updater,
dns_rpz_update_taskaction, zone, &zone->updatetimer);
/*
* This will never be used, but costs us nothing and
@ -1573,14 +1567,6 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) {
*rpzp = zone;
return (ISC_R_SUCCESS);
cleanup_timer:
isc_refcount_decrementz(&zone->refs);
isc_refcount_destroy(&zone->refs);
isc_mem_put(rpzs->mctx, zone, sizeof(*zone));
return (result);
}
isc_result_t
@ -1630,8 +1616,8 @@ dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
isc_interval_set(&interval, (unsigned int)defer, 0);
dns_db_currentversion(zone->db, &zone->dbversion);
result = isc_timer_reset(zone->updatetimer,
isc_timertype_once, NULL,
&interval, true);
isc_timertype_once, &interval,
true);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@ -1683,7 +1669,7 @@ dns_rpz_update_taskaction(isc_task_t *task, isc_event_t *event) {
zone->updaterunning = true;
dns_rpz_update_from_db(zone);
result = isc_timer_reset(zone->updatetimer, isc_timertype_inactive,
NULL, NULL, true);
NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = isc_time_now(&zone->lastupdated);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@ -1784,7 +1770,7 @@ finish_update(dns_rpz_zone_t *rpz) {
dname, defer);
isc_interval_set(&interval, (unsigned int)defer, 0);
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
NULL, &interval, true);
&interval, true);
} else {
isc_event_t *event = NULL;
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
@ -2224,7 +2210,7 @@ rpz_detach(dns_rpz_zone_t **rpzp) {
}
isc_timer_reset(rpz->updatetimer, isc_timertype_inactive, NULL,
NULL, true);
true);
isc_timer_detach(&rpz->updatetimer);
isc_ht_destroy(&rpz->nodes);

View file

@ -15272,18 +15272,22 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
if (isc_time_isepoch(&next)) {
zone_debuglog(zone, me, 10, "settimer inactive");
result = isc_timer_reset(zone->timer, isc_timertype_inactive,
NULL, NULL, true);
NULL, true);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"could not deactivate zone timer: %s",
isc_result_totext(result));
}
} else {
isc_interval_t interval;
if (isc_time_compare(&next, now) <= 0) {
next = *now;
isc_interval_set(&interval, 0, 1);
} else {
isc_time_subtract(&next, now, &interval);
}
result = isc_timer_reset(zone->timer, isc_timertype_once, &next,
NULL, true);
result = isc_timer_reset(zone->timer, isc_timertype_once,
&interval, true);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"could not reset zone timer: %s",
@ -18946,8 +18950,6 @@ dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) {
isc_result_t
dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
isc_result_t result;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
@ -18972,13 +18974,8 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
isc_task_setname(zone->task, "zone", zone);
isc_task_setname(zone->loadtask, "loadzone", zone);
result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive, NULL,
NULL, zone->task, zone_timer, zone,
&zone->timer);
if (result != ISC_R_SUCCESS) {
goto cleanup_tasks;
}
isc_timer_create(zmgr->timermgr, zone->task, zone_timer, zone,
&zone->timer);
/*
* The timer "holds" a iref.
@ -18991,16 +18988,9 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
zone->zmgr = zmgr;
isc_refcount_increment(&zmgr->refs);
goto unlock;
cleanup_tasks:
isc_task_detach(&zone->loadtask);
isc_task_detach(&zone->task);
unlock:
UNLOCK_ZONE(zone);
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
return (result);
return (ISC_R_SUCCESS);
}
void
@ -22485,7 +22475,6 @@ dns_zone_getserialupdatemethod(dns_zone_t *zone) {
*/
isc_result_t
dns_zone_link(dns_zone_t *zone, dns_zone_t *raw) {
isc_result_t result;
dns_zonemgr_t *zmgr;
REQUIRE(DNS_ZONE_VALID(zone));
@ -22510,12 +22499,8 @@ dns_zone_link(dns_zone_t *zone, dns_zone_t *raw) {
LOCK_ZONE(zone);
LOCK_ZONE(raw);
result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive, NULL,
NULL, zone->task, zone_timer, raw,
&raw->timer);
if (result != ISC_R_SUCCESS) {
goto unlock;
}
isc_timer_create(zmgr->timermgr, zone->task, zone_timer, raw,
&raw->timer);
/*
* The timer "holds" a iref.
@ -22536,11 +22521,10 @@ dns_zone_link(dns_zone_t *zone, dns_zone_t *raw) {
raw->zmgr = zmgr;
isc_refcount_increment(&zmgr->refs);
unlock:
UNLOCK_ZONE(raw);
UNLOCK_ZONE(zone);
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
return (result);
return (ISC_R_SUCCESS);
}
void

View file

@ -31,6 +31,7 @@
#include <stdbool.h>
#include <isc/lang.h>
#include <isc/time.h>
#include <isc/types.h>
ISC_LANG_BEGINDECLS

View file

@ -21,24 +21,6 @@
#include <isc/lang.h>
#include <isc/types.h>
/***
*** Intervals
***/
/*!
* \brief
* The contents of this structure are private, and MUST NOT be accessed
* directly by callers.
*
* The contents are exposed only to allow callers to avoid dynamic allocation.
*/
struct isc_interval {
unsigned int seconds;
unsigned int nanoseconds;
};
extern const isc_interval_t *const isc_interval_zero;
/*
* ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially
* more for other locales to handle longer national abbreviations when
@ -46,11 +28,16 @@ extern const isc_interval_t *const isc_interval_zero;
*/
#define ISC_FORMATHTTPTIMESTAMP_SIZE 50
/*
* Semantic shims to distinguish between relative and absolute time
*/
#define isc_interval_zero isc_time_epoch
#define isc_interval_t isc_time_t
ISC_LANG_BEGINDECLS
void
isc_interval_set(isc_interval_t *i, unsigned int seconds,
unsigned int nanoseconds);
#define isc_interval_set(i, seconds, nanoseconds) \
isc_time_set((isc_time_t *)i, seconds, nanoseconds)
/*%<
* Set 'i' to a value representing an interval of 'seconds' seconds and
* 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
@ -62,8 +49,7 @@ isc_interval_set(isc_interval_t *i, unsigned int seconds,
*\li nanoseconds < 1000000000.
*/
bool
isc_interval_iszero(const isc_interval_t *i);
#define isc_interval_iszero(i) isc_time_isepoch((const isc_time_t *)i)
/*%<
* Returns true iff. 'i' is the zero interval.
*
@ -72,8 +58,7 @@ isc_interval_iszero(const isc_interval_t *i);
*\li 'i' is a valid pointer.
*/
unsigned int
isc_interval_ms(const isc_interval_t *i);
#define isc_interval_ms(i) isc_time_miliseconds((const isc_time_t *)i)
/*%<
* Returns interval 'i' expressed as a number of milliseconds.
*
@ -320,6 +305,16 @@ isc_time_nanoseconds(const isc_time_t *t);
*\li The returned value is less than 1*10^9.
*/
uint32_t
isc_time_miliseconds(const isc_time_t *t);
/*%<
* Returns time 't' expressed as a number of milliseconds.
*
* Requires:
*
*\li 't' is a valid pointer.
*/
void
isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
/*%<

View file

@ -24,13 +24,8 @@
*
*\li 'ticker' timers generate a periodic tick event.
*
*\li 'once' timers generate an idle timeout event if they are idle for too
* long, and generate a life timeout event if their lifetime expires.
* They are used to implement both (possibly expiring) idle timers and
* 'one-shot' timers.
*
*\li 'limited' timers generate a periodic tick event until they reach
* their lifetime when they generate a life timeout event.
*\li 'once' timers generate an timeout event if the time reaches
* the set interval.
*
*\li 'inactive' timers generate no events.
*
@ -83,7 +78,6 @@ typedef enum {
isc_timertype_undefined = -1, /*%< Undefined */
isc_timertype_ticker = 0, /*%< Ticker */
isc_timertype_once = 1, /*%< Once */
isc_timertype_limited = 2, /*%< Limited */
isc_timertype_inactive = 3 /*%< Inactive */
} isc_timertype_t;
@ -94,8 +88,7 @@ typedef struct isc_timerevent {
#define ISC_TIMEREVENT_FIRSTEVENT (ISC_EVENTCLASS_TIMER + 0)
#define ISC_TIMEREVENT_TICK (ISC_EVENTCLASS_TIMER + 1)
#define ISC_TIMEREVENT_IDLE (ISC_EVENTCLASS_TIMER + 2)
#define ISC_TIMEREVENT_LIFE (ISC_EVENTCLASS_TIMER + 3)
#define ISC_TIMEREVENT_ONCE (ISC_EVENTCLASS_TIMER + 2)
#define ISC_TIMEREVENT_LASTEVENT (ISC_EVENTCLASS_TIMER + 65535)
/***
@ -105,32 +98,15 @@ typedef struct isc_timerevent {
*** those functions which return an isc_result_t.
***/
isc_result_t
isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
const isc_time_t *expires, const isc_interval_t *interval,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_timer_t **timerp);
void
isc_timer_create(isc_timermgr_t *manager, isc_task_t *task,
isc_taskaction_t action, void *arg, isc_timer_t **timerp);
/*%<
* Create a new 'type' timer managed by 'manager'. The timers parameters
* are specified by 'expires' and 'interval'. Events will be posted to
* 'task' and when dispatched 'action' will be called with 'arg' as the
* arg value. The new timer is returned in 'timerp'.
*
* Notes:
*
*\li For ticker timers, the timer will generate a 'tick' event every
* 'interval' seconds. The value of 'expires' is ignored.
*
*\li For once timers, 'expires' specifies the time when a life timeout
* event should be generated. If 'expires' is 0 (the epoch), then no life
* timeout will be generated. 'interval' specifies how long the timer
* can be idle before it generates an idle timeout. If 0, then no
* idle timeout will be generated.
*
*\li If 'expires' is NULL, the epoch will be used.
*
* If 'interval' is NULL, the zero interval will be used.
*
* Requires:
*
*\li 'manager' is a valid manager
@ -167,16 +143,20 @@ isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
isc_result_t
isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
const isc_time_t *expires, const isc_interval_t *interval,
bool purge);
const isc_interval_t *interval, bool purge);
/*%<
* Change the timer's type, expires, and interval values to the given
* Change the timer's type, and interval values to the given
* values. If 'purge' is TRUE, any pending events from this timer
* are purged from its task's event queue.
*
* Notes:
*
*\li If 'expires' is NULL, the epoch will be used.
*\li For ticker timers, the timer will generate a 'tick' event every
* 'interval' seconds.
*
*\li For once timers, 'interval' specifies how long the timer
* can be idle before it generates an idle timeout. If 0, then no
* idle timeout will be generated.
*
*\li If 'interval' is NULL, the zero interval will be used.
*
@ -184,8 +164,8 @@ isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
*
*\li 'timer' is a valid timer
*
*\li The same requirements that isc_timer_create() imposes on 'type',
* 'expires' and 'interval' apply.
*\li 'interval' points to a valid interval, or is NULL.
*
*
* Ensures:
*
@ -200,27 +180,6 @@ isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
*\li Unexpected error
*/
isc_result_t
isc_timer_touch(isc_timer_t *timer);
/*%<
* Set the last-touched time of 'timer' to the current time.
*
* Requires:
*
*\li 'timer' is a valid once timer.
*
* Ensures:
*
*\li An idle timeout will not be generated until at least Now + the
* timer's interval if 'timer' is a once timer with a non-zero
* interval.
*
* Returns:
*
*\li Success
*\li Unexpected error
*/
void
isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp);
/*%<
@ -277,7 +236,4 @@ isc_timer_gettype(isc_timer_t *timer);
*\li 'timer' to be a valid timer.
*/
void
isc_timermgr_poke(isc_timermgr_t *m);
ISC_LANG_ENDDECLS

View file

@ -55,7 +55,6 @@ typedef struct isc_httpdurl isc_httpdurl_t; /*%< HTTP URL */
typedef void(isc_httpdondestroy_t)(void *); /*%< Callback on destroying httpd */
typedef struct isc_interface isc_interface_t; /*%< Interface */
typedef struct isc_interfaceiter isc_interfaceiter_t; /*%< Interface Iterator */
typedef struct isc_interval isc_interval_t; /*%< Interval */
typedef struct isc_lex isc_lex_t; /*%< Lex */
typedef struct isc_log isc_log_t; /*%< Log */
typedef struct isc_logcategory isc_logcategory_t; /*%< Log Category */

View file

@ -56,7 +56,6 @@ ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event);
isc_result_t
isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
isc_task_t *task, isc_ratelimiter_t **ratelimiterp) {
isc_result_t result;
isc_ratelimiter_t *rl;
INSIST(ratelimiterp != NULL && *ratelimiterp == NULL);
@ -74,11 +73,7 @@ isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
isc_mutex_init(&rl->lock);
result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
rl->task, ratelimiter_tick, rl, &rl->timer);
if (result != ISC_R_SUCCESS) {
goto free_mutex;
}
isc_timer_create(timermgr, rl->task, ratelimiter_tick, rl, &rl->timer);
/*
* Increment the reference count to indicate that we may
@ -92,13 +87,6 @@ isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
*ratelimiterp = rl;
return (ISC_R_SUCCESS);
free_mutex:
isc_refcount_decrementz(&rl->references);
isc_refcount_destroy(&rl->references);
isc_mutex_destroy(&rl->lock);
isc_mem_put(mctx, rl, sizeof(*rl));
return (result);
}
isc_result_t
@ -114,7 +102,7 @@ isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *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,
result = isc_timer_reset(rl->timer, isc_timertype_ticker,
&rl->interval, false);
}
UNLOCK(&rl->lock);
@ -162,7 +150,7 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
ISC_LIST_APPEND(rl->pending, ev, ev_ratelink);
}
} else if (rl->state == isc_ratelimiter_idle) {
result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
result = isc_timer_reset(rl->timer, isc_timertype_ticker,
&rl->interval, false);
if (result == ISC_R_SUCCESS) {
ev->ev_sender = task;
@ -223,8 +211,7 @@ ratelimiter_tick(isc_task_t *task, isc_event_t *event) {
* waste resources by having it fire periodically.
*/
isc_result_t result = isc_timer_reset(
rl->timer, isc_timertype_inactive, NULL, NULL,
false);
rl->timer, isc_timertype_inactive, NULL, false);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
rl->state = isc_ratelimiter_idle;
pertic = 0; /* Force the loop to exit. */
@ -247,8 +234,7 @@ isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
LOCK(&rl->lock);
rl->state = isc_ratelimiter_shuttingdown;
(void)isc_timer_reset(rl->timer, isc_timertype_inactive, NULL, NULL,
false);
(void)isc_timer_reset(rl->timer, isc_timertype_inactive, NULL, false);
while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) {
task = ev->ev_sender;
ISC_LIST_UNLINK(rl->pending, ev, ev_ratelink);
@ -323,7 +309,7 @@ isc_ratelimiter_stall(isc_ratelimiter_t *rl) {
break;
case isc_ratelimiter_ratelimited:
result = isc_timer_reset(rl->timer, isc_timertype_inactive,
NULL, NULL, false);
NULL, false);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/* FALLTHROUGH */
case isc_ratelimiter_idle:
@ -349,7 +335,7 @@ isc_ratelimiter_release(isc_ratelimiter_t *rl) {
case isc_ratelimiter_stalled:
if (!ISC_LIST_EMPTY(rl->pending)) {
result = isc_timer_reset(rl->timer,
isc_timertype_ticker, NULL,
isc_timertype_ticker,
&rl->interval, false);
if (result == ISC_R_SUCCESS) {
rl->state = isc_ratelimiter_ratelimited;

View file

@ -480,7 +480,6 @@ basic(void **state) {
isc_event_t *event = NULL;
isc_timer_t *ti1 = NULL;
isc_timer_t *ti2 = NULL;
isc_time_t absolute;
isc_interval_t interval;
char *testarray[] = { one, one, one, one, one, one, one, one,
one, two, three, four, two, three, four, NULL };
@ -506,17 +505,15 @@ basic(void **state) {
result = isc_task_onshutdown(task4, basic_shutdown, four);
assert_int_equal(result, ISC_R_SUCCESS);
isc_time_settoepoch(&absolute);
isc_interval_set(&interval, 1, 0);
result = isc_timer_create(timermgr, isc_timertype_ticker, &absolute,
&interval, task1, basic_tick, tick, &ti1);
isc_timer_create(timermgr, task1, basic_tick, tick, &ti1);
result = isc_timer_reset(ti1, isc_timertype_ticker, &interval, false);
assert_int_equal(result, ISC_R_SUCCESS);
ti2 = NULL;
isc_time_settoepoch(&absolute);
isc_interval_set(&interval, 1, 0);
result = isc_timer_create(timermgr, isc_timertype_ticker, &absolute,
&interval, task2, basic_tick, tock, &ti2);
isc_timer_create(timermgr, task2, basic_tick, tock, &ti2);
result = isc_timer_reset(ti2, isc_timertype_ticker, &interval, false);
assert_int_equal(result, ISC_R_SUCCESS);
sleep(2);

View file

@ -102,8 +102,7 @@ shutdown(isc_task_t *task, isc_event_t *event) {
}
static void
setup_test(isc_timertype_t timertype, isc_time_t *expires,
isc_interval_t *interval,
setup_test(isc_timertype_t timertype, isc_interval_t *interval,
void (*action)(isc_task_t *, isc_event_t *)) {
isc_result_t result;
isc_task_t *task = NULL;
@ -130,8 +129,8 @@ setup_test(isc_timertype_t timertype, isc_time_t *expires,
isc_mutex_unlock(&lasttime_mx);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_timer_create(timermgr, timertype, expires, interval, task,
action, (void *)timertype, &timer);
isc_timer_create(timermgr, task, action, (void *)timertype, &timer);
result = isc_timer_reset(timer, timertype, interval, false);
assert_int_equal(result, ISC_R_SUCCESS);
/*
@ -207,7 +206,7 @@ ticktock(isc_task_t *task, isc_event_t *event) {
print_message("# tick %d\n", tick);
}
expected_event_type = ISC_TIMEREVENT_LIFE;
expected_event_type = ISC_TIMEREVENT_ONCE;
if ((uintptr_t)event->ev_arg == isc_timertype_ticker) {
expected_event_type = ISC_TIMEREVENT_TICK;
}
@ -259,7 +258,6 @@ ticktock(isc_task_t *task, isc_event_t *event) {
/* timer type ticker */
static void
ticker(void **state) {
isc_time_t expires;
isc_interval_t interval;
UNUSED(state);
@ -269,31 +267,8 @@ ticker(void **state) {
nanoseconds = 500000000;
isc_interval_set(&interval, seconds, nanoseconds);
isc_time_settoepoch(&expires);
setup_test(isc_timertype_ticker, &expires, &interval, ticktock);
}
/* timer type once reaches lifetime */
static void
once_life(void **state) {
isc_result_t result;
isc_time_t expires;
isc_interval_t interval;
UNUSED(state);
nevents = 1;
seconds = 1;
nanoseconds = 100000000;
isc_interval_set(&interval, seconds, nanoseconds);
result = isc_time_nowplusinterval(&expires, &interval);
assert_int_equal(result, ISC_R_SUCCESS);
isc_interval_set(&interval, 0, 0);
setup_test(isc_timertype_once, &expires, &interval, ticktock);
setup_test(isc_timertype_ticker, &interval, ticktock);
}
static void
@ -335,7 +310,7 @@ test_idle(isc_task_t *task, isc_event_t *event) {
isc_time_add(&now, &interval, &lasttime);
isc_mutex_unlock(&lasttime_mx);
subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_IDLE);
subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_ONCE);
isc_timer_detach(&timer);
isc_task_shutdown(task);
@ -345,8 +320,6 @@ test_idle(isc_task_t *task, isc_event_t *event) {
/* timer type once idles out */
static void
once_idle(void **state) {
isc_result_t result;
isc_time_t expires;
isc_interval_t interval;
UNUSED(state);
@ -355,13 +328,9 @@ once_idle(void **state) {
seconds = 1;
nanoseconds = 200000000;
isc_interval_set(&interval, seconds + 1, nanoseconds);
result = isc_time_nowplusinterval(&expires, &interval);
assert_int_equal(result, ISC_R_SUCCESS);
isc_interval_set(&interval, seconds, nanoseconds);
setup_test(isc_timertype_once, &expires, &interval, test_idle);
setup_test(isc_timertype_once, &interval, test_idle);
}
/* timer reset */
@ -372,7 +341,6 @@ test_reset(isc_task_t *task, isc_event_t *event) {
isc_time_t base;
isc_time_t ulim;
isc_time_t llim;
isc_time_t expires;
isc_interval_t interval;
int tick = atomic_fetch_add(&eventcnt, 1);
@ -413,19 +381,14 @@ test_reset(isc_task_t *task, isc_event_t *event) {
if (_eventcnt < 3) {
subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_TICK);
if (_eventcnt == 2) {
isc_interval_set(&interval, seconds, nanoseconds);
result = isc_time_nowplusinterval(&expires, &interval);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
isc_interval_set(&interval, 0, 0);
result = isc_timer_reset(timer, isc_timertype_once,
&expires, &interval, false);
&interval, false);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
}
} else {
subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_LIFE);
subthread_assert_int_equal(event->ev_type, ISC_TIMEREVENT_ONCE);
isc_timer_detach(&timer);
isc_task_shutdown(task);
@ -436,7 +399,6 @@ test_reset(isc_task_t *task, isc_event_t *event) {
static void
reset(void **state) {
isc_time_t expires;
isc_interval_t interval;
UNUSED(state);
@ -446,9 +408,8 @@ reset(void **state) {
nanoseconds = 750000000;
isc_interval_set(&interval, seconds, nanoseconds);
isc_time_settoepoch(&expires);
setup_test(isc_timertype_ticker, &expires, &interval, test_reset);
setup_test(isc_timertype_ticker, &interval, test_reset);
}
static atomic_bool startflag;
@ -492,7 +453,7 @@ tick_event(isc_task_t *task, isc_event_t *event) {
isc_time_settoepoch(&expires);
isc_interval_set(&interval, seconds, 0);
result = isc_timer_reset(tickertimer, isc_timertype_ticker,
&expires, &interval, true);
&interval, true);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
isc_task_shutdown(task);
@ -537,7 +498,6 @@ shutdown_purge(isc_task_t *task, isc_event_t *event) {
static void
purge(void **state) {
isc_result_t result;
isc_time_t expires;
isc_interval_t interval;
UNUSED(state);
@ -557,25 +517,21 @@ purge(void **state) {
result = isc_task_create(taskmgr, 0, &task2);
assert_int_equal(result, ISC_R_SUCCESS);
isc_time_settoepoch(&expires);
isc_interval_set(&interval, seconds, 0);
tickertimer = NULL;
result = isc_timer_create(timermgr, isc_timertype_ticker, &expires,
&interval, task1, tick_event, NULL,
&tickertimer);
isc_timer_create(timermgr, task1, tick_event, NULL, &tickertimer);
result = isc_timer_reset(tickertimer, isc_timertype_ticker, &interval,
false);
assert_int_equal(result, ISC_R_SUCCESS);
oncetimer = NULL;
isc_interval_set(&interval, (seconds * 2) + 1, 0);
result = isc_time_nowplusinterval(&expires, &interval);
assert_int_equal(result, ISC_R_SUCCESS);
isc_interval_set(&interval, 0, 0);
result = isc_timer_create(timermgr, isc_timertype_once, &expires,
&interval, task2, once_event, NULL,
&oncetimer);
isc_timer_create(timermgr, task2, once_event, NULL, &oncetimer);
result = isc_timer_reset(oncetimer, isc_timertype_once, &interval,
false);
assert_int_equal(result, ISC_R_SUCCESS);
/*
@ -598,8 +554,9 @@ purge(void **state) {
int
main(int argc, char **argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(ticker), cmocka_unit_test(once_life),
cmocka_unit_test(once_idle), cmocka_unit_test(reset),
cmocka_unit_test(ticker),
cmocka_unit_test(once_idle),
cmocka_unit_test(reset),
cmocka_unit_test(purge),
};
int c;

View file

@ -51,49 +51,6 @@
#define CLOCKSOURCE_HIRES CLOCKSOURCE
#endif /* #ifndef CLOCKSOURCE_HIRES */
/*%
*** Intervals
***/
#if !defined(UNIT_TESTING)
static const isc_interval_t zero_interval = { 0, 0 };
const isc_interval_t *const isc_interval_zero = &zero_interval;
#endif
void
isc_interval_set(isc_interval_t *i, unsigned int seconds,
unsigned int nanoseconds) {
REQUIRE(i != NULL);
REQUIRE(nanoseconds < NS_PER_S);
i->seconds = seconds;
i->nanoseconds = nanoseconds;
}
bool
isc_interval_iszero(const isc_interval_t *i) {
REQUIRE(i != NULL);
INSIST(i->nanoseconds < NS_PER_S);
if (i->seconds == 0 && i->nanoseconds == 0) {
return (true);
}
return (false);
}
unsigned int
isc_interval_ms(const isc_interval_t *i) {
REQUIRE(i != NULL);
INSIST(i->nanoseconds < NS_PER_S);
return ((i->seconds * MS_PER_S) + (i->nanoseconds / NS_PER_MS));
}
/***
*** Absolute Times
***/
#if !defined(UNIT_TESTING)
static const isc_time_t epoch = { 0, 0 };
const isc_time_t *const isc_time_epoch = &epoch;
@ -131,11 +88,11 @@ isc_time_isepoch(const isc_time_t *t) {
static inline isc_result_t
time_now(isc_time_t *t, clockid_t clock) {
struct timespec ts;
char strbuf[ISC_STRERRORSIZE];
REQUIRE(t != NULL);
if (clock_gettime(clock, &ts) == -1) {
char strbuf[ISC_STRERRORSIZE];
strerror_r(errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
return (ISC_R_UNEXPECTED);
@ -173,13 +130,13 @@ isc_time_now(isc_time_t *t) {
isc_result_t
isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
struct timespec ts;
char strbuf[ISC_STRERRORSIZE];
REQUIRE(t != NULL);
REQUIRE(i != NULL);
INSIST(i->nanoseconds < NS_PER_S);
if (clock_gettime(CLOCKSOURCE, &ts) == -1) {
char strbuf[ISC_STRERRORSIZE];
strerror_r(errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
return (ISC_R_UNEXPECTED);
@ -373,6 +330,14 @@ isc_time_nanoseconds(const isc_time_t *t) {
return ((uint32_t)t->nanoseconds);
}
uint32_t
isc_time_miliseconds(const isc_time_t *t) {
REQUIRE(t != NULL);
INSIST(t->nanoseconds < NS_PER_S);
return ((t->seconds * MS_PER_S) + (t->nanoseconds / NS_PER_MS));
}
void
isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
time_t now;

View file

@ -64,7 +64,6 @@ struct isc_timer {
isc_time_t idle;
/*! Locked by manager lock. */
isc_timertype_t type;
isc_time_t expires;
isc_interval_t interval;
isc_task_t *task;
isc_taskaction_t action;
@ -92,46 +91,34 @@ struct isc_timermgr {
isc_heap_t *heap;
};
void
isc_timermgr_poke(isc_timermgr_t *manager);
static inline isc_result_t
static isc_result_t
schedule(isc_timer_t *timer, isc_time_t *now, bool signal_ok) {
isc_timermgr_t *manager;
isc_time_t due;
isc_result_t result = ISC_R_SUCCESS;
/*!
* Note: the caller must ensure locking.
*/
REQUIRE(timer->type != isc_timertype_inactive);
manager = timer->manager;
/*
* Compute the new due time.
*/
if (timer->type != isc_timertype_once) {
isc_result_t result = isc_time_add(now, &timer->interval, &due);
switch (timer->type) {
case isc_timertype_ticker:
result = isc_time_add(now, &timer->interval, &due);
if (result != ISC_R_SUCCESS) {
return (result);
}
if (timer->type == isc_timertype_limited &&
isc_time_compare(&timer->expires, &due) < 0)
{
due = timer->expires;
}
} else {
if (isc_time_isepoch(&timer->idle)) {
due = timer->expires;
} else if (isc_time_isepoch(&timer->expires)) {
due = timer->idle;
} else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
{
due = timer->idle;
} else {
due = timer->expires;
}
break;
case isc_timertype_once:
due = timer->idle;
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
/*
@ -175,10 +162,10 @@ schedule(isc_timer_t *timer, isc_time_t *now, bool signal_ok) {
SIGNAL(&manager->wakeup);
}
return (ISC_R_SUCCESS);
return (result);
}
static inline void
static void
deschedule(isc_timer_t *timer) {
isc_timermgr_t *manager;
@ -227,123 +214,58 @@ destroy(isc_timer_t *timer) {
isc_mem_put(manager->mctx, timer, sizeof(*timer));
}
isc_result_t
isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
const isc_time_t *expires, const isc_interval_t *interval,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_timer_t **timerp) {
void
isc_timer_create(isc_timermgr_t *manager, isc_task_t *task,
isc_taskaction_t action, void *arg, isc_timer_t **timerp) {
REQUIRE(VALID_MANAGER(manager));
REQUIRE(task != NULL);
REQUIRE(action != NULL);
isc_timer_t *timer;
isc_result_t result;
isc_time_t now;
/*
* Create a new 'type' timer managed by 'manager'. The timers
* parameters are specified by 'expires' and 'interval'. Events
* will be posted to 'task' and when dispatched 'action' will be
* called with 'arg' as the arg value. The new timer is returned
* in 'timerp'.
*/
if (expires == NULL) {
expires = isc_time_epoch;
}
if (interval == NULL) {
interval = isc_interval_zero;
}
REQUIRE(type == isc_timertype_inactive ||
!(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
REQUIRE(timerp != NULL && *timerp == NULL);
REQUIRE(type != isc_timertype_limited ||
!(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
/*
* Get current time.
*/
if (type != isc_timertype_inactive) {
TIME_NOW(&now);
} else {
/*
* We don't have to do this, but it keeps the compiler from
* complaining about "now" possibly being used without being
* set, even though it will never actually happen.
*/
isc_time_settoepoch(&now);
}
TIME_NOW(&now);
timer = isc_mem_get(manager->mctx, sizeof(*timer));
*timer = (isc_timer_t){
.manager = manager,
.type = isc_timertype_inactive,
.interval = *isc_interval_zero,
.action = action,
.arg = arg,
};
timer->manager = manager;
isc_refcount_init(&timer->references, 1);
if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
result = isc_time_add(&now, interval, &timer->idle);
if (result != ISC_R_SUCCESS) {
isc_mem_put(manager->mctx, timer, sizeof(*timer));
return (result);
}
} else {
isc_time_settoepoch(&timer->idle);
}
isc_time_settoepoch(&timer->idle);
timer->type = type;
timer->expires = *expires;
timer->interval = *interval;
timer->task = NULL;
isc_task_attach(task, &timer->task);
timer->action = action;
/*
* Removing the const attribute from "arg" is the best of two
* evils here. If the timer->arg member is made const, then
* it affects a great many recipients of the timer event
* which did not pass in an "arg" that was truly const.
* Changing isc_timer_create() to not have "arg" prototyped as const,
* though, can cause compilers warnings for calls that *do*
* have a truly const arg. The caller will have to carefully
* keep track of whether arg started as a true const.
*/
DE_CONST(arg, timer->arg);
timer->index = 0;
isc_mutex_init(&timer->lock);
ISC_LINK_INIT(timer, link);
timer->magic = TIMER_MAGIC;
LOCK(&manager->lock);
timer->magic = TIMER_MAGIC;
/*
* Note we don't have to lock the timer like we normally would because
* there are no external references to it yet.
*/
if (type != isc_timertype_inactive) {
result = schedule(timer, &now, true);
} else {
result = ISC_R_SUCCESS;
}
if (result == ISC_R_SUCCESS) {
*timerp = timer;
APPEND(manager->timers, timer, link);
}
*timerp = timer;
LOCK(&manager->lock);
APPEND(manager->timers, timer, link);
UNLOCK(&manager->lock);
if (result != ISC_R_SUCCESS) {
timer->magic = 0;
isc_mutex_destroy(&timer->lock);
isc_task_detach(&timer->task);
isc_mem_put(manager->mctx, timer, sizeof(*timer));
return (result);
}
return (ISC_R_SUCCESS);
}
isc_result_t
isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
const isc_time_t *expires, const isc_interval_t *interval,
bool purge) {
const isc_interval_t *interval, bool purge) {
isc_time_t now;
isc_timermgr_t *manager;
isc_result_t result;
@ -358,16 +280,11 @@ isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
manager = timer->manager;
REQUIRE(VALID_MANAGER(manager));
if (expires == NULL) {
expires = isc_time_epoch;
}
if (interval == NULL) {
interval = isc_interval_zero;
}
REQUIRE(type == isc_timertype_inactive ||
!(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
REQUIRE(type != isc_timertype_limited ||
!(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
!isc_interval_iszero(interval));
/*
* Get current time.
@ -392,7 +309,6 @@ isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
ISC_TIMEREVENT_LASTEVENT, NULL);
}
timer->type = type;
timer->expires = *expires;
timer->interval = *interval;
if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
result = isc_time_add(&now, interval, &timer->idle);
@ -429,36 +345,6 @@ isc_timer_gettype(isc_timer_t *timer) {
return (t);
}
isc_result_t
isc_timer_touch(isc_timer_t *timer) {
isc_result_t result;
isc_time_t now;
/*
* Set the last-touched time of 'timer' to the current time.
*/
REQUIRE(VALID_TIMER(timer));
LOCK(&timer->lock);
/*
* We'd like to
*
* REQUIRE(timer->type == isc_timertype_once);
*
* but we cannot without locking the manager lock too, which we
* don't want to do.
*/
TIME_NOW(&now);
result = isc_time_add(&now, &timer->interval, &timer->idle);
UNLOCK(&timer->lock);
return (result);
}
void
isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) {
REQUIRE(VALID_TIMER(timer));
@ -488,107 +374,73 @@ isc_timer_detach(isc_timer_t **timerp) {
}
static void
dispatch(isc_timermgr_t *manager, isc_time_t *now) {
bool done = false, post_event, need_schedule;
post_event(isc_timermgr_t *manager, isc_timer_t *timer, isc_eventtype_t type) {
isc_timerevent_t *event;
XTRACEID("posting", timer);
/*
* XXX We could preallocate this event.
*/
event = (isc_timerevent_t *)isc_event_allocate(
manager->mctx, timer, type, timer->action, timer->arg,
sizeof(*event));
if (event != NULL) {
event->due = timer->due;
isc_task_send(timer->task, ISC_EVENT_PTR(&event));
} else {
UNEXPECTED_ERROR(__FILE__, __LINE__, "%s",
"couldn't allocate event");
}
}
static void
dispatch(isc_timermgr_t *manager, isc_time_t *now) {
bool need_schedule;
isc_eventtype_t type = 0;
isc_timer_t *timer;
isc_result_t result;
bool idle;
/*!
* The caller must be holding the manager lock.
*/
while (manager->nscheduled > 0 && !done) {
while (manager->nscheduled > 0) {
timer = isc_heap_element(manager->heap, 1);
INSIST(timer != NULL && timer->type != isc_timertype_inactive);
if (isc_time_compare(now, &timer->due) >= 0) {
if (timer->type == isc_timertype_ticker) {
type = ISC_TIMEREVENT_TICK;
post_event = true;
need_schedule = true;
} else if (timer->type == isc_timertype_limited) {
int cmp;
cmp = isc_time_compare(now, &timer->expires);
if (cmp >= 0) {
type = ISC_TIMEREVENT_LIFE;
post_event = true;
need_schedule = false;
} else {
type = ISC_TIMEREVENT_TICK;
post_event = true;
need_schedule = true;
}
} else if (!isc_time_isepoch(&timer->expires) &&
isc_time_compare(now, &timer->expires) >= 0)
{
type = ISC_TIMEREVENT_LIFE;
post_event = true;
need_schedule = false;
} else {
idle = false;
LOCK(&timer->lock);
if (!isc_time_isepoch(&timer->idle) &&
isc_time_compare(now, &timer->idle) >= 0) {
idle = true;
}
UNLOCK(&timer->lock);
if (idle) {
type = ISC_TIMEREVENT_IDLE;
post_event = true;
need_schedule = false;
} else {
/*
* Idle timer has been touched;
* reschedule.
*/
XTRACEID("idle reschedule", timer);
post_event = false;
need_schedule = true;
}
}
if (post_event) {
XTRACEID("posting", timer);
/*
* XXX We could preallocate this event.
*/
event = (isc_timerevent_t *)isc_event_allocate(
manager->mctx, timer, type,
timer->action, timer->arg,
sizeof(*event));
if (event != NULL) {
event->due = timer->due;
isc_task_send(timer->task,
ISC_EVENT_PTR(&event));
} else {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"%s",
"couldn't allocate "
"event");
}
}
timer->index = 0;
isc_heap_delete(manager->heap, 1);
manager->nscheduled--;
if (need_schedule) {
result = schedule(timer, now, false);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"%s: %u",
"couldn't schedule "
"timer",
result);
}
}
} else {
if (isc_time_compare(now, &timer->due) < 0) {
manager->due = timer->due;
done = true;
break;
}
switch (timer->type) {
case isc_timertype_ticker:
type = ISC_TIMEREVENT_TICK;
post_event(manager, timer, type);
need_schedule = true;
break;
case isc_timertype_once:
type = ISC_TIMEREVENT_ONCE;
post_event(manager, timer, type);
need_schedule = false;
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
timer->index = 0;
isc_heap_delete(manager->heap, 1);
manager->nscheduled--;
if (need_schedule) {
result = schedule(timer, now, false);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: %u",
"couldn't schedule "
"timer",
result);
}
}
}
}
@ -680,13 +532,6 @@ isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
return (ISC_R_SUCCESS);
}
void
isc_timermgr_poke(isc_timermgr_t *manager) {
REQUIRE(VALID_MANAGER(manager));
SIGNAL(&manager->wakeup);
}
void
isc__timermgr_destroy(isc_timermgr_t **managerp) {
isc_timermgr_t *manager;