From: Oto Šťáva Date: Wed, 22 May 2024 13:18:30 +0000 (+0200) Subject: daemon/session2: support multiple short-lived buffers X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eda967fe453d8c6777219fc8f4c8a3ae12e37cdd;p=thirdparty%2Fknot-resolver.git daemon/session2: support multiple short-lived buffers It might be needed when RRL implements postponing of contexts. --- diff --git a/daemon/io.c b/daemon/io.c index d19da0ebd..dfad835e7 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -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); } diff --git a/daemon/session2.c b/daemon/session2.c index 818300d86..7ce0dddf1 100644 --- a/daemon/session2.c +++ b/daemon/session2.c @@ -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); } diff --git a/daemon/session2.h b/daemon/session2.h index ac83d8dec..985fa31e6 100644 --- a/daemon/session2.h +++ b/daemon/session2.h @@ -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`. */