From 466a56b499331091c9bca7a3ca53b1ea9f2f8264 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 23 Oct 2026 12:20:34 +0200 Subject: [PATCH] Add allocation-free queue discard for terminal stream resets --- lib/ll_queue.c | 40 ++++++++++++++++++++++++++-------------- lib/ll_queue.h | 6 ++++++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/lib/ll_queue.c b/lib/ll_queue.c index 60106bb0..359f206d 100644 --- a/lib/ll_queue.c +++ b/lib/ll_queue.c @@ -129,15 +129,7 @@ struct ll_entry* ll_alloc_lldgram(uint16_t len) { return entry; } -void queue_free(struct ll_queue* q) { - if (!q) return; - - DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_free: freeing queue %p, head=%p, tail=%p, count=%d", - q, q->head, q->tail, q->count); - - // ВАЖНО: Не освобождаем элементы в очереди - они должны быть извлечены отдельно - // Это упрощает архитектуру и предотвращает double-u_free - +static void queue_cancel_notifications(struct ll_queue* q) { while (q->deferred_waiters) queue_waiter_cancel(q, q->deferred_waiters); // Освободить список waiters (сбросить handle->internal, отменить отложенные вызовы) struct queue_waiter* w = q->waiter_head; @@ -150,11 +142,6 @@ void queue_free(struct ll_queue* q) { q->waiter_head = NULL; q->waiter_tail = NULL; - // Освободить хеш-таблицу - if (q->hash_table) { - u_free(q->hash_table); - } - // Отменить отложенное возобновление if (q->resume_timeout_id) { uasync_call_soon_cancel(q->ua, q->resume_timeout_id); @@ -170,6 +157,31 @@ void queue_free(struct ll_queue* q) { q->on_get_arg = NULL; if (q->on_get_call_soon_id) uasync_call_soon_cancel(q->ua, q->on_get_call_soon_id); q->on_get_call_soon_id = NULL; q->on_get_pending = 0; + q->callback_suspended = 1; +} + +void queue_clear(struct ll_queue* q) { + if (!q) return; +#ifdef QUEUE_THREAD_CHECK + queue_check_thread(q); +#endif + DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "[%s] discard queue: packets=%d bytes=%zu", q->name, q->count, q->total_bytes); + queue_cancel_notifications(q); + struct ll_entry* entry = q->head; + q->head = q->tail = NULL; q->count = 0; q->total_bytes = 0; + if (q->hash_table) memset(q->hash_table, 0, q->hash_size * sizeof(*q->hash_table)); + while (entry) { + struct ll_entry* next = entry->next; + entry->owner = NULL; entry->next = entry->prev = entry->hash_next = NULL; + queue_dgram_free(entry); queue_entry_free(entry); entry = next; + } +} + +void queue_free(struct ll_queue* q) { + if (!q) return; + DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_free: freeing queue %p, head=%p, count=%d", (void*)q, (void*)q->head, q->count); + queue_cancel_notifications(q); + if (q->hash_table) u_free(q->hash_table); if (q->head) DEBUG_WARN(DEBUG_CATEGORY_SYS, "[%s] freeing nonempty queue: count=%d; entries remain caller-owned", q->name, q->count); for (struct ll_entry* e = q->head; e; e = e->next) e->owner = NULL; diff --git a/lib/ll_queue.h b/lib/ll_queue.h index a98647a1..518c5483 100644 --- a/lib/ll_queue.h +++ b/lib/ll_queue.h @@ -205,6 +205,12 @@ struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, uint16_t index_o */ void queue_free(struct ll_queue* q); +/* Аварийный сброс: освободить все entry/dgram, отменить waiters и отложенные уведомления без их вызова. + * Не выделяет память (кроме действий пользовательского dgram_free_fn). Очередь/индекс/обычный callback/пороги сохраняются. + * empty/on_get обработчики снимаются, callback приостановлен; владельцы заново ставят ожидания после восстановления. + * Вызывать в потоке ua; NULL допустим. Для продолжения автозабора нужен queue_resume_callback(). */ +void queue_clear(struct ll_queue* q); + // ==================== Конфигурация ==================== /**