diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 15e330f0d1..a7a04fab57 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -645,7 +645,7 @@ struct dns_notify { dns_tsigkey_t *key; dns_transport_t *transport; ISC_LINK(dns_notify_t) link; - isc_event_t *event; + isc_rlevent_t *rlevent; }; #define DNS_NOTIFY_NOSOA 0x0001U @@ -665,7 +665,7 @@ struct dns_checkds { dns_tsigkey_t *key; dns_transport_t *transport; ISC_LINK(dns_checkds_t) link; - isc_event_t *event; + isc_rlevent_t *rlevent; }; /*% @@ -884,7 +884,7 @@ stub_callback(isc_task_t *, isc_event_t *); static void queue_soa_query(dns_zone_t *zone); static void -soa_query(isc_task_t *, isc_event_t *); +soa_query(void *arg); static void ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub); static int @@ -898,7 +898,7 @@ checkds_createmessage(dns_zone_t *zone, dns_message_t **messagep); static void checkds_done(isc_task_t *task, isc_event_t *event); static void -checkds_send_toaddr(isc_task_t *task, isc_event_t *event); +checkds_send_toaddr(void *arg); static void notify_cancel(dns_zone_t *zone); static void @@ -911,7 +911,7 @@ notify_createmessage(dns_zone_t *zone, unsigned int flags, static void notify_done(isc_task_t *task, isc_event_t *event); static void -notify_send_toaddr(isc_task_t *task, isc_event_t *event); +notify_send_toaddr(void *arg); static isc_result_t zone_dump(dns_zone_t *, bool); static void @@ -11975,22 +11975,21 @@ requeue: * not a startup notify, re-enqueue on the normal notify * ratelimiter. */ - if (notify->event != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 && + if (notify->rlevent != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 && (notify->flags & DNS_NOTIFY_STARTUP) != 0) { zmgr = notify->zone->zmgr; result = isc_ratelimiter_dequeue(zmgr->startupnotifyrl, - notify->event); + ¬ify->rlevent); if (result != ISC_R_SUCCESS) { return (true); } notify->flags &= ~DNS_NOTIFY_STARTUP; - result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl, - notify->zone->task, - ¬ify->event); + result = isc_ratelimiter_enqueue( + notify->zone->zmgr->notifyrl, notify->zone->loop, + notify_send_toaddr, notify, ¬ify->rlevent); if (result != ISC_R_SUCCESS) { - isc_event_free(¬ify->event); return (false); } } @@ -12176,31 +12175,16 @@ destroy: static isc_result_t notify_send_queue(dns_notify_t *notify, bool startup) { - isc_event_t *e; - isc_result_t result; - - INSIST(notify->event == NULL); - e = isc_event_allocate(notify->mctx, NULL, DNS_EVENT_NOTIFYSENDTOADDR, - notify_send_toaddr, notify, sizeof(isc_event_t)); - if (startup) { - notify->event = e; - } - e->ev_arg = notify; - e->ev_sender = NULL; - result = isc_ratelimiter_enqueue( + return (isc_ratelimiter_enqueue( startup ? notify->zone->zmgr->startupnotifyrl : notify->zone->zmgr->notifyrl, - notify->zone->task, &e); - if (result != ISC_R_SUCCESS) { - isc_event_free(&e); - notify->event = NULL; - } - return (result); + notify->zone->loop, notify_send_toaddr, notify, + ¬ify->rlevent)); } static void -notify_send_toaddr(isc_task_t *task, isc_event_t *event) { - dns_notify_t *notify; +notify_send_toaddr(void *arg) { + dns_notify_t *notify = (dns_notify_t *)arg; isc_result_t result; dns_message_t *message = NULL; isc_netaddr_t dstip; @@ -12210,21 +12194,12 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) { unsigned int options, timeout; bool have_notifysource = false; - notify = event->ev_arg; REQUIRE(DNS_NOTIFY_VALID(notify)); - UNUSED(task); - LOCK_ZONE(notify->zone); - notify->event = NULL; - - if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0) { - result = ISC_R_CANCELED; - goto cleanup; - } - - if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 || + if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0 || + notify->rlevent->canceled || DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING) || notify->zone->view->requestmgr == NULL || notify->zone->db == NULL) { @@ -12350,7 +12325,7 @@ cleanup_message: dns_message_detach(&message); cleanup: UNLOCK_ZONE(notify->zone); - isc_event_free(&event); + isc_rlevent_free(¬ify->rlevent); if (result != ISC_R_SUCCESS) { notify_destroy(notify, false); } @@ -13991,11 +13966,15 @@ detach: return; } +struct soaquery { + dns_zone_t *zone; + isc_rlevent_t *rlevent; +}; + static void queue_soa_query(dns_zone_t *zone) { - isc_event_t *e; - dns_zone_t *dummy = NULL; isc_result_t result; + struct soaquery *sq = NULL; ENTER; /* @@ -14008,31 +13987,28 @@ queue_soa_query(dns_zone_t *zone) { return; } - e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE, soa_query, - zone, sizeof(isc_event_t)); + sq = isc_mem_get(zone->mctx, sizeof(*sq)); + *sq = (struct soaquery){ .zone = NULL }; /* - * Attach so that we won't clean up - * until the event is delivered. + * Attach so that we won't clean up until the event is delivered. */ - zone_iattach(zone, &dummy); - - e->ev_arg = zone; - e->ev_sender = NULL; - result = isc_ratelimiter_enqueue(zone->zmgr->refreshrl, zone->task, &e); + zone_iattach(zone, &sq->zone); + result = isc_ratelimiter_enqueue(zone->zmgr->refreshrl, zone->loop, + soa_query, sq, &sq->rlevent); if (result != ISC_R_SUCCESS) { - zone_idetach(&dummy); - isc_event_free(&e); + zone_idetach(&sq->zone); + isc_mem_put(zone->mctx, sq, sizeof(*sq)); cancel_refresh(zone); } } static void -soa_query(isc_task_t *task, isc_event_t *event) { +soa_query(void *arg) { + struct soaquery *sq = (struct soaquery *)arg; + dns_zone_t *zone = sq->zone; isc_result_t result = ISC_R_FAILURE; dns_message_t *message = NULL; - dns_zone_t *zone = event->ev_arg; - dns_zone_t *dummy = NULL; isc_netaddr_t primaryip; dns_tsigkey_t *key = NULL; dns_transport_t *transport = NULL; @@ -14046,13 +14022,10 @@ soa_query(isc_task_t *task, isc_event_t *event) { REQUIRE(DNS_ZONE_VALID(zone)); - UNUSED(task); - ENTER; LOCK_ZONE(zone); - if (((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) || - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || + if (sq->rlevent->canceled || DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || zone->view->requestmgr == NULL) { if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { @@ -14198,7 +14171,7 @@ again: } } - zone_iattach(zone, &dummy); + zone_iattach(zone, &(dns_zone_t *){ NULL }); timeout = 15; if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) { timeout = 30; @@ -14208,7 +14181,7 @@ again: NULL, NULL, options, key, timeout * 3, timeout, 2, zone->task, refresh_callback, zone, &zone->request); if (result != ISC_R_SUCCESS) { - zone_idetach(&dummy); + zone_idetach(&(dns_zone_t *){ zone }); zone_debuglog(zone, __func__, 1, "dns_request_create() failed: %s", isc_result_totext(result)); @@ -14237,11 +14210,12 @@ cleanup: if (cancel) { cancel_refresh(zone); } - isc_event_free(&event); UNLOCK_ZONE(zone); if (do_queue_xfrin) { queue_xfrin(zone); } + isc_rlevent_free(&sq->rlevent); + isc_mem_put(zone->mctx, sq, sizeof(*sq)); dns_zone_idetach(&zone); return; @@ -19725,8 +19699,6 @@ dnssec_report(const char *format, ...) { static void checkds_destroy(dns_checkds_t *checkds, bool locked) { - isc_mem_t *mctx; - REQUIRE(DNS_CHECKDS_VALID(checkds)); dns_zone_log(checkds->zone, ISC_LOG_DEBUG(3), @@ -19759,9 +19731,8 @@ checkds_destroy(dns_checkds_t *checkds, bool locked) { if (checkds->transport != NULL) { dns_transport_detach(&checkds->transport); } - mctx = checkds->mctx; - isc_mem_put(checkds->mctx, checkds, sizeof(*checkds)); - isc_mem_detach(&mctx); + INSIST(checkds->rlevent == NULL); + isc_mem_putanddetach(&checkds->mctx, checkds, sizeof(*checkds)); } static isc_result_t @@ -20173,8 +20144,8 @@ checkds_createmessage(dns_zone_t *zone, dns_message_t **messagep) { } static void -checkds_send_toaddr(isc_task_t *task, isc_event_t *event) { - dns_checkds_t *checkds; +checkds_send_toaddr(void *arg) { + dns_checkds_t *checkds = (dns_checkds_t *)arg; isc_result_t result; dns_message_t *message = NULL; isc_netaddr_t dstip; @@ -20183,22 +20154,15 @@ checkds_send_toaddr(isc_task_t *task, isc_event_t *event) { isc_sockaddr_t src; unsigned int options, timeout; bool have_checkdssource = false; + bool canceled = checkds->rlevent->canceled; - checkds = event->ev_arg; REQUIRE(DNS_CHECKDS_VALID(checkds)); - UNUSED(task); + isc_rlevent_free(&checkds->rlevent); LOCK_ZONE(checkds->zone); - checkds->event = NULL; - - if (DNS_ZONE_FLAG(checkds->zone, DNS_ZONEFLG_LOADED) == 0) { - result = ISC_R_CANCELED; - goto cleanup; - } - - if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 || + if (DNS_ZONE_FLAG(checkds->zone, DNS_ZONEFLG_LOADED) == 0 || canceled || DNS_ZONE_FLAG(checkds->zone, DNS_ZONEFLG_EXITING) || checkds->zone->view->requestmgr == NULL || checkds->zone->db == NULL) @@ -20321,32 +20285,11 @@ cleanup_message: dns_message_detach(&message); cleanup: UNLOCK_ZONE(checkds->zone); - isc_event_free(&event); if (result != ISC_R_SUCCESS) { checkds_destroy(checkds, false); } } -static isc_result_t -checkds_send_queue(dns_checkds_t *checkds) { - isc_event_t *e; - isc_result_t result; - - INSIST(checkds->event == NULL); - e = isc_event_allocate(checkds->mctx, NULL, DNS_EVENT_CHECKDSSENDTOADDR, - checkds_send_toaddr, checkds, - sizeof(isc_event_t)); - e->ev_arg = checkds; - e->ev_sender = NULL; - result = isc_ratelimiter_enqueue(checkds->zone->zmgr->checkdsrl, - checkds->zone->task, &e); - if (result != ISC_R_SUCCESS) { - isc_event_free(&e); - checkds->event = NULL; - } - return (result); -} - static void checkds_send(dns_zone_t *zone) { dns_view_t *view = dns_zone_getview(zone); @@ -20444,7 +20387,9 @@ checkds_send(dns_zone_t *zone) { } ISC_LIST_APPEND(zone->checkds_requests, checkds, link); - result = checkds_send_queue(checkds); + result = isc_ratelimiter_enqueue( + checkds->zone->zmgr->checkdsrl, checkds->zone->loop, + checkds_send_toaddr, checkds, &checkds->rlevent); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_DEBUG(3), "checkds: send DS query to " diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h index 1f4b8d2d7e..d5510cf978 100644 --- a/lib/isc/include/isc/ratelimiter.h +++ b/lib/isc/include/isc/ratelimiter.h @@ -35,6 +35,15 @@ #include #include +struct isc_rlevent { + isc_loop_t *loop; + isc_ratelimiter_t *rl; + bool canceled; + isc_job_cb cb; + void *arg; + ISC_LINK(isc_rlevent_t) link; +}; + ISC_LANG_BEGINDECLS /***** @@ -48,7 +57,8 @@ isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **rlp); */ void -isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval); +isc_ratelimiter_setinterval(isc_ratelimiter_t *restrict rl, + const isc_interval_t *const interval); /*!< * Set the minimum interval between event executions. * The interval value is copied, so the caller need not preserve it. @@ -58,45 +68,47 @@ isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval); */ void -isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, uint32_t perint); +isc_ratelimiter_setpertic(isc_ratelimiter_t *restrict rl, + const uint32_t perint); /*%< * Set the number of events processed per interval timer tick. * If 'perint' is zero it is treated as 1. */ void -isc_ratelimiter_setpushpop(isc_ratelimiter_t *rl, bool pushpop); +isc_ratelimiter_setpushpop(isc_ratelimiter_t *restrict rl, const bool pushpop); /*%< * Set / clear the ratelimiter to from push pop mode rather * first in - first out mode (default). */ isc_result_t -isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, - isc_event_t **eventp); +isc_ratelimiter_enqueue(isc_ratelimiter_t *restrict rl, + isc_loop_t *restrict loop, isc_job_cb cb, void *arg, + isc_rlevent_t **rlep); /*%< * Queue an event for rate-limited execution. * - * This is similar - * to doing an isc_task_send() to the 'task', except that the - * execution may be delayed to achieve the desired rate of + * This is similar to doing an isc_async_run() to the 'loop', except + * that the execution may be delayed to achieve the desired rate of * execution. * - * '(*eventp)->ev_sender' is used to hold the task. The caller - * must ensure that the task exists until the event is delivered. + * '*rlep' will be set to point to an allocated ratelimiter event, + * which can be freed by the caller using isc_rlevent_free() when the + * event fires, or by dequeueing. * * Requires: - *\li An interval has been set by calling - * isc_ratelimiter_setinterval(). - * - *\li 'task' to be non NULL. - *\li '(*eventp)->ev_sender' to be NULL. + *\li 'rl' is a valid ratelimiter. + *\li 'loop ' is non NULL. + *\li 'rlep' is non NULL and '*rlep' is NULL. */ isc_result_t -isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event); +isc_ratelimiter_dequeue(isc_ratelimiter_t *restrict rl, + isc_rlevent_t **rleventp); /* - * Dequeue a event off the ratelimiter queue. + * Dequeue a event off the ratelimiter queue. If the event has not already + * been posted, it will be freed and '*rleventp' will be set to NULL. * * Returns: * \li ISC_R_NOTFOUND if the event is no longer linked to the rate limiter. @@ -104,19 +116,22 @@ isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event); */ void -isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter); +isc_ratelimiter_shutdown(isc_ratelimiter_t *restrict rl); /*%< * Shut down a rate limiter. * * Ensures: - *\li All events that have not yet been - * dispatched to the task are dispatched immediately with - * the #ISC_EVENTATTR_CANCELED bit set in ev_attributes. + *\li All pending events are dispatched immediately with + * rle->canceled set to true. * *\li Further attempts to enqueue events will fail with * #ISC_R_SHUTTINGDOWN. - * - *\li The rate limiter is no longer attached to its task. + */ + +void +isc_rlevent_free(isc_rlevent_t **rlep); +/*%< + * Free the rate limiter event '*rlep'. */ ISC_REFCOUNT_DECL(isc_ratelimiter); diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index 475cc1f411..a3ef04698f 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -71,6 +71,7 @@ typedef struct isc_portset isc_portset_t; /*%< Port Set */ typedef struct isc_quota isc_quota_t; /*%< Quota */ typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */ typedef struct isc_region isc_region_t; /*%< Region */ +typedef struct isc_rlevent isc_rlevent_t; /*%< Rate Limiter Event */ typedef struct isc_signal isc_signal_t; /*%< Signal handler */ typedef struct isc_sockaddr isc_sockaddr_t; /*%< Socket Address */ typedef ISC_LIST(isc_sockaddr_t) isc_sockaddrlist_t; /*%< Socket Address List diff --git a/lib/isc/ratelimiter.c b/lib/isc/ratelimiter.c index 07bc45c236..8873600acc 100644 --- a/lib/isc/ratelimiter.c +++ b/lib/isc/ratelimiter.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -48,7 +47,7 @@ struct isc_ratelimiter { uint32_t pertic; bool pushpop; isc_ratelimiter_state_t state; - ISC_LIST(isc_event_t) pending; + ISC_LIST(isc_rlevent_t) pending; }; static void @@ -91,7 +90,8 @@ isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **rlp) { } void -isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) { +isc_ratelimiter_setinterval(isc_ratelimiter_t *restrict rl, + const isc_interval_t *const interval) { REQUIRE(VALID_RATELIMITER(rl)); REQUIRE(interval != NULL); @@ -102,7 +102,8 @@ isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) { } void -isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, uint32_t pertic) { +isc_ratelimiter_setpertic(isc_ratelimiter_t *restrict rl, + const uint32_t pertic) { REQUIRE(VALID_RATELIMITER(rl)); REQUIRE(pertic > 0); @@ -112,7 +113,7 @@ isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, uint32_t pertic) { } void -isc_ratelimiter_setpushpop(isc_ratelimiter_t *rl, bool pushpop) { +isc_ratelimiter_setpushpop(isc_ratelimiter_t *restrict rl, const bool pushpop) { REQUIRE(VALID_RATELIMITER(rl)); LOCK(&rl->lock); @@ -152,16 +153,15 @@ isc__ratelimiter_start(void *arg) { } isc_result_t -isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, - isc_event_t **eventp) { +isc_ratelimiter_enqueue(isc_ratelimiter_t *restrict rl, + isc_loop_t *restrict loop, isc_job_cb cb, void *arg, + isc_rlevent_t **rlep) { isc_result_t result = ISC_R_SUCCESS; - isc_event_t *event; + isc_rlevent_t *rle = NULL; REQUIRE(VALID_RATELIMITER(rl)); - REQUIRE(task != NULL); - REQUIRE(eventp != NULL && *eventp != NULL); - event = *eventp; - REQUIRE(event->ev_sender == NULL); + REQUIRE(loop != NULL); + REQUIRE(rlep != NULL && *rlep == NULL); LOCK(&rl->lock); switch (rl->state) { @@ -175,13 +175,21 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, rl->state = isc_ratelimiter_ratelimited; FALLTHROUGH; case isc_ratelimiter_ratelimited: - event->ev_sender = task; - *eventp = NULL; + rle = isc_mem_get(isc_loop_getmctx(loop), sizeof(*rle)); + *rle = (isc_rlevent_t){ + .cb = cb, + .arg = arg, + .link = ISC_LINK_INITIALIZER, + }; + isc_loop_attach(loop, &rle->loop); + isc_ratelimiter_attach(rl, &rle->rl); + if (rl->pushpop) { - ISC_LIST_PREPEND(rl->pending, event, ev_ratelink); + ISC_LIST_PREPEND(rl->pending, rle, link); } else { - ISC_LIST_APPEND(rl->pending, event, ev_ratelink); + ISC_LIST_APPEND(rl->pending, rle, link); } + *rlep = rle; break; default: UNREACHABLE(); @@ -191,30 +199,29 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, } isc_result_t -isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event) { +isc_ratelimiter_dequeue(isc_ratelimiter_t *restrict rl, isc_rlevent_t **rlep) { isc_result_t result = ISC_R_SUCCESS; REQUIRE(rl != NULL); - REQUIRE(event != NULL); + REQUIRE(rlep != NULL); LOCK(&rl->lock); - if (ISC_LINK_LINKED(event, ev_ratelink)) { - ISC_LIST_UNLINK(rl->pending, event, ev_ratelink); - event->ev_sender = NULL; + if (ISC_LINK_LINKED(*rlep, link)) { + ISC_LIST_UNLINK(rl->pending, *rlep, link); + isc_rlevent_free(rlep); } else { result = ISC_R_NOTFOUND; } UNLOCK(&rl->lock); - return (result); } static void isc__ratelimiter_tick(void *arg) { isc_ratelimiter_t *rl = (isc_ratelimiter_t *)arg; - isc_event_t *event; + isc_rlevent_t *rle = NULL; uint32_t pertic; - ISC_LIST(isc_event_t) pending; + ISC_LIST(isc_rlevent_t) pending; REQUIRE(VALID_RATELIMITER(rl)); @@ -231,11 +238,11 @@ isc__ratelimiter_tick(void *arg) { pertic = rl->pertic; while (pertic != 0) { - event = ISC_LIST_HEAD(rl->pending); - if (event != NULL) { + rle = ISC_LIST_HEAD(rl->pending); + if (rle != NULL) { /* There is work to do. Let's do it after unlocking. */ - ISC_LIST_UNLINK(rl->pending, event, ev_ratelink); - ISC_LIST_APPEND(pending, event, ev_ratelink); + ISC_LIST_UNLINK(rl->pending, rle, link); + ISC_LIST_APPEND(pending, rle, link); } else { /* * We processed all the scheduled work, but there's a @@ -257,9 +264,9 @@ isc__ratelimiter_tick(void *arg) { unlock: UNLOCK(&rl->lock); - while ((event = ISC_LIST_HEAD(pending)) != NULL) { - ISC_LIST_UNLINK(pending, event, ev_ratelink); - isc_task_send(event->ev_sender, &event); + while ((rle = ISC_LIST_HEAD(pending)) != NULL) { + ISC_LIST_UNLINK(pending, rle, link); + isc_async_run(rle->loop, rle->cb, rle->arg); } } @@ -281,9 +288,9 @@ isc__ratelimiter_doshutdown(void *arg) { } void -isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) { - isc_event_t *event; - ISC_LIST(isc_event_t) pending; +isc_ratelimiter_shutdown(isc_ratelimiter_t *restrict rl) { + isc_rlevent_t *rle = NULL; + ISC_LIST(isc_rlevent_t) pending; REQUIRE(VALID_RATELIMITER(rl)); @@ -298,15 +305,15 @@ isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) { } UNLOCK(&rl->lock); - while ((event = ISC_LIST_HEAD(pending)) != NULL) { - ISC_LIST_UNLINK(pending, event, ev_ratelink); - event->ev_attributes |= ISC_EVENTATTR_CANCELED; - isc_task_send(event->ev_sender, &event); + while ((rle = ISC_LIST_HEAD(pending)) != NULL) { + ISC_LIST_UNLINK(pending, rle, link); + rle->canceled = true; + isc_async_run(rl->loop, rle->cb, rle->arg); } } static void -ratelimiter_destroy(isc_ratelimiter_t *rl) { +ratelimiter_destroy(isc_ratelimiter_t *restrict rl) { isc_refcount_destroy(&rl->references); LOCK(&rl->lock); @@ -317,4 +324,18 @@ ratelimiter_destroy(isc_ratelimiter_t *rl) { isc_mem_putanddetach(&rl->mctx, rl, sizeof(*rl)); } +void +isc_rlevent_free(isc_rlevent_t **rlep) { + REQUIRE(rlep != NULL && *rlep != NULL); + + isc_rlevent_t *rle = *rlep; + isc_mem_t *mctx = isc_loop_getmctx(rle->loop); + + *rlep = NULL; + + isc_loop_detach(&rle->loop); + isc_ratelimiter_detach(&rle->rl); + isc_mem_put(mctx, rle, sizeof(*rle)); +} + ISC_REFCOUNT_IMPL(isc_ratelimiter, ratelimiter_destroy); diff --git a/tests/isc/ratelimiter_test.c b/tests/isc/ratelimiter_test.c index 81c0a71b02..848902d7b9 100644 --- a/tests/isc/ratelimiter_test.c +++ b/tests/isc/ratelimiter_test.c @@ -36,25 +36,25 @@ isc_ratelimiter_t *rl = NULL; +typedef struct rlstat { + isc_rlevent_t *event; +} rlstat_t; + ISC_LOOP_TEST_IMPL(ratelimiter_create) { - rl = NULL; + assert_null(rl); expect_assert_failure(isc_ratelimiter_create(NULL, &rl)); expect_assert_failure(isc_ratelimiter_create(mainloop, NULL)); - rl = (isc_ratelimiter_t *)&rl; - expect_assert_failure(isc_ratelimiter_create(mainloop, &rl)); + assert_null(rl); - rl = NULL; isc_ratelimiter_create(mainloop, &rl); isc_ratelimiter_shutdown(rl); - isc_ratelimiter_detach(&rl); isc_loopmgr_shutdown(loopmgr); } ISC_LOOP_TEST_IMPL(ratelimiter_shutdown) { - rl = NULL; - + assert_null(rl); expect_assert_failure(isc_ratelimiter_shutdown(NULL)); expect_assert_failure(isc_ratelimiter_shutdown(rl)); @@ -62,7 +62,7 @@ ISC_LOOP_TEST_IMPL(ratelimiter_shutdown) { } ISC_LOOP_TEST_IMPL(ratelimiter_detach) { - rl = NULL; + assert_null(rl); expect_assert_failure(isc_ratelimiter_detach(NULL)); expect_assert_failure(isc_ratelimiter_detach(&rl)); @@ -71,31 +71,28 @@ ISC_LOOP_TEST_IMPL(ratelimiter_detach) { } static int ticks = 0; -static isc_task_t *rl_task = NULL; static isc_time_t start_time; static isc_time_t tick_time; static void -tick(isc_task_t *task, isc_event_t *event) { - assert_ptr_equal(task, rl_task); - isc_event_free(&event); +tick(void *arg) { + rlstat_t *rlstat = (rlstat_t *)arg; + + isc_rlevent_free(&rlstat->event); + isc_mem_put(mctx, rlstat, sizeof(*rlstat)); ticks++; assert_int_equal(isc_time_now(&tick_time), ISC_R_SUCCESS); - isc_loopmgr_shutdown(loopmgr); - - isc_task_detach(&rl_task); isc_ratelimiter_shutdown(rl); isc_ratelimiter_detach(&rl); + + isc_loopmgr_shutdown(loopmgr); } ISC_LOOP_SETUP_IMPL(ratelimiter_common) { - isc_result_t result = isc_task_create(taskmgr, &rl_task, 0); - assert_int_equal(result, ISC_R_SUCCESS); - - rl = NULL; + assert_null(rl); isc_time_set(&tick_time, 0, 0); assert_int_equal(isc_time_now(&start_time), ISC_R_SUCCESS); isc_ratelimiter_create(mainloop, &rl); @@ -110,14 +107,12 @@ ISC_LOOP_TEARDOWN_IMPL(ratelimiter_enqueue) { assert_int_equal(ticks, 1); } ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_enqueue) { isc_result_t result; - isc_event_t *event = NULL; + rlstat_t *rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - - result = isc_ratelimiter_enqueue(rl, rl_task, &event); + result = isc_ratelimiter_enqueue(rl, mainloop, tick, rlstat, + &rlstat->event); assert_int_equal(result, ISC_R_SUCCESS); + assert_non_null(rlstat->event); } ISC_LOOP_SETUP_IMPL(ratelimiter_enqueue_shutdown) { @@ -130,31 +125,27 @@ ISC_LOOP_TEARDOWN_IMPL(ratelimiter_enqueue_shutdown) { } ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_enqueue_shutdown) { - isc_event_t *event = NULL; + rlstat_t *rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); + isc_rlevent_t *event = NULL; - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - - expect_assert_failure(isc_ratelimiter_enqueue(NULL, rl_task, &event)); - expect_assert_failure(isc_ratelimiter_enqueue(rl, NULL, &event)); - expect_assert_failure(isc_ratelimiter_enqueue(rl, rl_task, NULL)); expect_assert_failure( - isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ NULL })); + isc_ratelimiter_enqueue(NULL, mainloop, tick, NULL, &event)); + expect_assert_failure( + isc_ratelimiter_enqueue(rl, NULL, tick, NULL, &event)); + expect_assert_failure( + isc_ratelimiter_enqueue(rl, mainloop, tick, NULL, NULL)); - assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + assert_int_equal(isc_ratelimiter_enqueue(rl, mainloop, tick, rlstat, + &rlstat->event), ISC_R_SUCCESS); + assert_non_null(rlstat->event); isc_ratelimiter_shutdown(rl); - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - - assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), - ISC_R_SHUTTINGDOWN); - - isc_event_free(&event); + assert_int_equal( + isc_ratelimiter_enqueue(rl, mainloop, tick, NULL, &event), + ISC_R_SHUTTINGDOWN); + assert_null(event); } ISC_LOOP_SETUP_IMPL(ratelimiter_dequeue) { @@ -163,38 +154,43 @@ ISC_LOOP_SETUP_IMPL(ratelimiter_dequeue) { } ISC_LOOP_TEARDOWN_IMPL(ratelimiter_dequeue) { /* */ - assert_int_equal(ticks, 1); + assert_int_equal(ticks, 0); } ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_dequeue) { - isc_event_t *event = NULL; + rlstat_t *rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); + isc_rlevent_t *fake = isc_mem_get(mctx, sizeof(*fake)); - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - assert_int_equal( - isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }), - ISC_R_SUCCESS); - assert_int_equal(isc_ratelimiter_dequeue(rl, event), ISC_R_SUCCESS); - isc_event_free(&event); - assert_null(event); - - /* This event didn't get scheduled */ - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - assert_int_equal(isc_ratelimiter_dequeue(rl, event), ISC_R_NOTFOUND); - assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + assert_int_equal(isc_ratelimiter_enqueue(rl, mainloop, tick, rlstat, + &rlstat->event), ISC_R_SUCCESS); - assert_null(event); + assert_int_equal(isc_ratelimiter_dequeue(rl, &rlstat->event), + ISC_R_SUCCESS); + isc_mem_put(mctx, rlstat, sizeof(*rlstat)); + + /* Set up a mock ratelimiter event that isn't actually scheduled */ + *fake = (isc_rlevent_t){ .link = ISC_LINK_INITIALIZER }; + isc_loop_attach(mainloop, &fake->loop); + isc_ratelimiter_attach(rl, &fake->rl); + assert_int_equal(isc_ratelimiter_dequeue(rl, &fake), ISC_R_NOTFOUND); + isc_loop_detach(&fake->loop); + isc_ratelimiter_detach(&fake->rl); + isc_mem_put(mctx, fake, sizeof(*fake)); + + isc_ratelimiter_shutdown(rl); + isc_ratelimiter_detach(&rl); + + isc_loopmgr_shutdown(loopmgr); } static isc_time_t tock_time; static void -tock(isc_task_t *task, isc_event_t *event) { - assert_ptr_equal(task, rl_task); - isc_event_free(&event); +tock(void *arg) { + rlstat_t *rlstat = (rlstat_t *)arg; + + isc_rlevent_free(&rlstat->event); + isc_mem_put(mctx, rlstat, sizeof(*rlstat)); ticks++; assert_int_equal(isc_time_now(&tock_time), ISC_R_SUCCESS); @@ -216,7 +212,7 @@ ISC_LOOP_TEARDOWN_IMPL(ratelimiter_pertick_interval) { } ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pertick_interval) { - isc_event_t *event = NULL; + rlstat_t *rlstat = NULL; isc_interval_t interval; isc_interval_set(&interval, 1, NS_PER_SEC / 10); @@ -231,18 +227,14 @@ ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pertick_interval) { isc_ratelimiter_setpertic(rl, 1); isc_ratelimiter_setpushpop(rl, false); - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tock, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - - assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); + assert_int_equal(isc_ratelimiter_enqueue(rl, mainloop, tock, rlstat, + &rlstat->event), ISC_R_SUCCESS); - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - - assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); + assert_int_equal(isc_ratelimiter_enqueue(rl, mainloop, tick, rlstat, + &rlstat->event), ISC_R_SUCCESS); } @@ -259,7 +251,7 @@ ISC_LOOP_TEARDOWN_IMPL(ratelimiter_pushpop) { } ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pushpop) { - isc_event_t *event = NULL; + rlstat_t *rlstat = NULL; isc_interval_t interval; isc_interval_set(&interval, 1, NS_PER_SEC / 10); @@ -268,21 +260,15 @@ ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pushpop) { isc_ratelimiter_setpertic(rl, 2); isc_ratelimiter_setpushpop(rl, true); - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, - sizeof(isc_event_t)); - assert_non_null(event); + rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); + assert_int_equal(isc_ratelimiter_enqueue(rl, mainloop, tock, rlstat, + &rlstat->event), + ISC_R_SUCCESS); - assert_int_equal( - isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }), - ISC_R_SUCCESS); - - event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tock, NULL, - sizeof(isc_event_t)); - assert_non_null(event); - - assert_int_equal( - isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }), - ISC_R_SUCCESS); + rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO); + assert_int_equal(isc_ratelimiter_enqueue(rl, mainloop, tick, rlstat, + &rlstat->event), + ISC_R_SUCCESS); } static int