]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/session2: support multiple short-lived buffers
authorOto Šťáva <oto.stava@nic.cz>
Wed, 22 May 2024 13:18:30 +0000 (15:18 +0200)
committerOto Šťáva <oto.stava@nic.cz>
Mon, 27 May 2024 12:02:30 +0000 (14:02 +0200)
It might be needed when RRL implements postponing of contexts.

daemon/io.c
daemon/session2.c
daemon/session2.h

index d19da0ebd801e87e8e823686cdebddc1acd76bdb..dfad835e71dcf24e6ffbba2b25232933efbc9597 100644 (file)
@@ -97,7 +97,7 @@ void udp_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
                .comm_addr = comm_addr,
                .src_addr = comm_addr
        };
-       session2_unwrap(s, protolayer_payload_wire_buf(&s->layers->wire_buf, false),
+       session2_unwrap(s, protolayer_payload_wire_buf(&s->layers->wire_buf, true),
                        &in_comm, udp_on_unwrapped, NULL);
 }
 
index 818300d862b9c8519fa97225708504ad2ffa1378..7ce0dddf121219fd6ab201a769797b14c86075aa 100644 (file)
@@ -181,6 +181,46 @@ static size_t iovecs_copy(void *dest, const struct iovec *iov, int cnt,
        return copy_size;
 }
 
+void *protolayer_buffer_list_add(struct protolayer_buffer_list *list, size_t n)
+{
+       struct protolayer_buffer_list_entry *e =
+                       malloc(sizeof(struct protolayer_buffer_list_entry) + n);
+       if (!e)
+               return NULL;
+
+       if (!list->head) {
+               if (kr_fails_assert(!list->tail)) {
+                       free(e);
+                       return NULL;
+               }
+
+               list->head = list->tail = e;
+               return e->data;
+       }
+
+       if (kr_fails_assert(list->tail)) {
+               free(e);
+               return NULL;
+       }
+
+       list->tail->next = e;
+       list->tail = e;
+       return e->data;
+}
+
+void protolayer_buffer_list_deinit(struct protolayer_buffer_list *list)
+{
+       struct protolayer_buffer_list_entry *e = list->head;
+       struct protolayer_buffer_list_entry *next;
+       while (e) {
+               next = e->next;
+               free(e);
+               e = next;
+       }
+       list->head = NULL;
+       list->tail = NULL;
+}
+
 size_t protolayer_payload_size(const struct protolayer_payload *payload)
 {
        switch (payload->type) {
@@ -411,7 +451,7 @@ static int protolayer_iter_ctx_finish(struct protolayer_iter_ctx *ctx, int ret)
                ctx->finished_cb(ret, session, &ctx->comm,
                                ctx->finished_cb_baton);
 
-       free(ctx->async_buffer);
+       protolayer_buffer_list_deinit(&ctx->async_buffer_list);
        free(ctx);
 
        return ret;
@@ -465,11 +505,10 @@ static void protolayer_payload_ensure_long_lived(struct protolayer_iter_ctx *ctx
        if (kr_fails_assert(buf_len))
                return;
 
-       void *buf = malloc(buf_len);
+       void *buf = protolayer_buffer_list_add(&ctx->async_buffer_list, buf_len);
        kr_require(buf);
        protolayer_payload_copy(buf, &ctx->payload, buf_len);
 
-       ctx->async_buffer = buf;
        ctx->payload = protolayer_payload_buffer(buf, buf_len, false);
 }
 
index ac83d8dec6c9de4100a97c828bdb789c022daaf6..985fa31e61bb194585ce10e179ab6b898702fd3e 100644 (file)
@@ -392,29 +392,59 @@ struct protolayer_payload {
        };
 };
 
+/** An entry in a linked list of buffers. The buffer data itself is allocated in
+ * the same object as the header. */
+struct protolayer_buffer_list_entry {
+       struct protolayer_buffer_list_entry *next;
+       alignas(CPU_STRUCT_ALIGN) char data[];
+};
+
+/** A linked list of buffers. */
+struct protolayer_buffer_list {
+       struct protolayer_buffer_list_entry *head;
+       struct protolayer_buffer_list_entry *tail;
+};
+
+/** Uses `malloc()` to allocate a new buffer of size `n` and adds it to the
+ * specified `list`. Returns a pointer to the buffer data (excl. the header) or
+ * `NULL` if the allocation fails. */
+void *protolayer_buffer_list_add(struct protolayer_buffer_list *list, size_t n);
+
+/** Frees the specified buffer list's entries (but not the list's control
+ * structure itself). */
+void protolayer_buffer_list_deinit(struct protolayer_buffer_list *list);
+
 /** Context for protocol layer iterations, containing payload data,
  * layer-specific data, and internal information for the protocol layer
  * manager. */
 struct protolayer_iter_ctx {
-/* read-write: */
+/* read-write for layers: */
        /** The payload */
        struct protolayer_payload payload;
        /** Communication information. Typically written into by one of the
         * first layers facilitating transport protocol processing. */
        struct comm_info comm;
 
-/* callback for when the layer iteration has ended - read-only: */
+/* callback for when the layer iteration has ended - read-only for layers: */
        protolayer_finished_cb finished_cb;
        void *finished_cb_baton;
 
-/* internal information for the manager - private: */
+/* internal information for the manager - should only be used by the protolayer
+ * system, never by layers: */
        enum protolayer_direction direction;
+       /** If `true`, the processing of layers has been paused and is waiting
+        * to be resumed or canceled. */
        bool async_mode;
+       /** The index of the layer that is currently being (or has just been)
+        * processed. */
        unsigned int layer_ix;
        struct protolayer_manager *manager;
+       /** Status passed to the finish callback. */
        int status;
        enum protolayer_iter_action action;
-       void *async_buffer;
+       /** Points to a buffers where data has been copied from short-lived
+        * payloads. Automatically freed together with the context. */
+       struct protolayer_buffer_list async_buffer_list;
 
        /** Contains a sequence of variably-sized CPU-aligned layer-specific
         * structs. See `struct protolayer_manager::data`. */