diff --git a/CHANGES b/CHANGES index 2fef963011..0224b17784 100644 --- a/CHANGES +++ b/CHANGES @@ -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] diff --git a/bin/named/control.c b/bin/named/control.c index d07896ecd5..29d1cd1f0f 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -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)) { diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index 29b56775fd..1ea4c490fb 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -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" diff --git a/bin/named/server.c b/bin/named/server.c index 2c5cc4253f..28bc75d89e 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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), diff --git a/cocci/isc_timer_reset.spatch b/cocci/isc_timer_reset.spatch new file mode 100644 index 0000000000..b89907f46c --- /dev/null +++ b/cocci/isc_timer_reset.spatch @@ -0,0 +1,6 @@ +@@ +expression E1, E2, E3, E4; +@@ + +- isc_timer_reset(E1, E2, NULL, E3, E4) ++ isc_timer_reset(E1, E2, E3, E4) diff --git a/doc/dev/dev.md b/doc/dev/dev.md index bf7aa94020..be26ba6a33 100644 --- a/doc/dev/dev.md +++ b/doc/dev/dev.md @@ -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()`. diff --git a/lib/dns/catz.c b/lib/dns/catz.c index 393d8454a5..3fc22aae77 100644 --- a/lib/dns/catz.c +++ b/lib/dns/catz.c @@ -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; } diff --git a/lib/dns/nta.c b/lib/dns/nta.c index 1c7a68dc54..49f4ddef47 100644 --- a/lib/dns/nta.c +++ b/lib/dns/nta.c @@ -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); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 2c5c50ab38..96e8a0cf99 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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); diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index 3b54ca6ca3..5905c8c1c1 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -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); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 7f9f8edcba..3cf0320970 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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 diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h index 45ec4470f1..828665418c 100644 --- a/lib/isc/include/isc/ratelimiter.h +++ b/lib/isc/include/isc/ratelimiter.h @@ -31,6 +31,7 @@ #include #include +#include #include ISC_LANG_BEGINDECLS diff --git a/lib/isc/include/isc/time.h b/lib/isc/include/isc/time.h index 8416927f02..5dff7f8b60 100644 --- a/lib/isc/include/isc/time.h +++ b/lib/isc/include/isc/time.h @@ -21,24 +21,6 @@ #include #include -/*** - *** 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); /*%< diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h index b86d74e4aa..1457d796f9 100644 --- a/lib/isc/include/isc/timer.h +++ b/lib/isc/include/isc/timer.h @@ -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 diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index c18b4f170e..78d5ce4a73 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -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 */ diff --git a/lib/isc/ratelimiter.c b/lib/isc/ratelimiter.c index dabbb08ff4..327144eb82 100644 --- a/lib/isc/ratelimiter.c +++ b/lib/isc/ratelimiter.c @@ -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; diff --git a/lib/isc/tests/task_test.c b/lib/isc/tests/task_test.c index f2cb18739c..0a4d91e5e5 100644 --- a/lib/isc/tests/task_test.c +++ b/lib/isc/tests/task_test.c @@ -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); diff --git a/lib/isc/tests/timer_test.c b/lib/isc/tests/timer_test.c index 8ff64c6da3..a41f7b8352 100644 --- a/lib/isc/tests/timer_test.c +++ b/lib/isc/tests/timer_test.c @@ -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; diff --git a/lib/isc/time.c b/lib/isc/time.c index 3e3cfd70b8..fa5f8bc345 100644 --- a/lib/isc/time.c +++ b/lib/isc/time.c @@ -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; diff --git a/lib/isc/timer.c b/lib/isc/timer.c index 30de75632f..720f972260 100644 --- a/lib/isc/timer.c +++ b/lib/isc/timer.c @@ -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;