]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
refactor isc_ratelimiter to use loop callbacks
authorEvan Hunt <each@isc.org>
Wed, 26 Oct 2022 01:35:41 +0000 (18:35 -0700)
committerEvan Hunt <each@isc.org>
Wed, 1 Feb 2023 05:41:19 +0000 (21:41 -0800)
the rate limter now uses loop callbacks rather than task events.
the API for isc_ratelimiter_enqueue() has been changed; we now pass
in a loop, a callback function and a callback argument, and
receive back a rate limiter event object (isc_rlevent_t). it
is no longer necessary for the caller to allocate the event.

the callback argument needs to include a pointer to the rlevent
object so that it can be freed using isc_rlevent_free(), or by
dequeueing.

lib/dns/zone.c
lib/isc/include/isc/ratelimiter.h
lib/isc/include/isc/types.h
lib/isc/ratelimiter.c
tests/isc/ratelimiter_test.c

index 15e330f0d13e31994a46525153e2e79a98d02fd3..a7a04fab57e634c3d89c0996ad1d4849f6cbea8f 100644 (file)
@@ -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);
+                                                &notify->rlevent);
                if (result != ISC_R_SUCCESS) {
                        return (true);
                }
 
                notify->flags &= ~DNS_NOTIFY_STARTUP;
-               result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl,
-                                                notify->zone->task,
-                                                &notify->event);
+               result = isc_ratelimiter_enqueue(
+                       notify->zone->zmgr->notifyrl, notify->zone->loop,
+                       notify_send_toaddr, notify, &notify->rlevent);
                if (result != ISC_R_SUCCESS) {
-                       isc_event_free(&notify->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,
+               &notify->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(&notify->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 "
index 1f4b8d2d7e2b6429a06eec345dfc9ad6b8d2f2b6..d5510cf97865da23a47dea4a19fb68af1a239243 100644 (file)
 #include <isc/time.h>
 #include <isc/types.h>
 
+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);
index 475cc1f411b50823fb92c5c68d0714525e89ca65..a3ef04698f3f9be8eb8be6f1a70f06d7729e8606 100644 (file)
@@ -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
index 07bc45c2365633025e4c4be5d28b5756ffbc7a5d..8873600acc9381a8f376ceaccb1bc78c92fc2fbc 100644 (file)
@@ -17,7 +17,6 @@
 #include <stdbool.h>
 
 #include <isc/async.h>
-#include <isc/event.h>
 #include <isc/loop.h>
 #include <isc/magic.h>
 #include <isc/mem.h>
@@ -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);
index 81c0a71b02462611c10603ba6c9bde5ded062c0c..848902d7b9989fdec1b1b27cc473b17697b304e4 100644 (file)
 
 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;
-
-       event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
-                                  sizeof(isc_event_t));
-       assert_non_null(event);
+       rlstat_t *rlstat = isc_mem_getx(mctx, sizeof(*rlstat), ISC_MEM_ZERO);
+       isc_rlevent_t *event = NULL;
 
-       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);
-
-       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);
+       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);
+       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