Сохранить текущее состояние перед исправлением компиляционных ошибок
This commit is contained in:
1 parent
abcda89800
commit
3f7fd9f8ad
50 files changed
+4272
-1772
No files matched your search
+150
@@ -0,0 +1,150 @@
|
||||
#ifndef LL_QUEUE_H
|
||||
#define LL_QUEUE_H
|
||||
|
||||
#include <stddef.h> // для size_t
|
||||
#include "memory_pool.h" // для struct memory_pool
|
||||
|
||||
// Предварительные объявления
|
||||
struct ll_queue;
|
||||
struct ll_entry;
|
||||
struct queue_waiter;
|
||||
struct memory_pool;
|
||||
|
||||
// Тип коллбэка: вызывается при добавлении элемента в пустую очередь или для продолжения обработки
|
||||
// Параметры: указатель на очередь, указатель на элемент (первый в очереди), пользовательский аргумент
|
||||
typedef void (*queue_callback_fn)(struct ll_queue* q, struct ll_entry* entry, void* arg);
|
||||
|
||||
// Структура элемента - переменный размер, данные расположены сразу после структуры
|
||||
struct ll_entry {
|
||||
struct ll_entry* next; // Указатель на следующий элемент в очереди
|
||||
size_t size; // Размер данных элемента (байт)
|
||||
int ref_count; // Счетчик ссылок для предотвращения double-free
|
||||
};
|
||||
|
||||
// Структура условия ожидания (waiter)
|
||||
struct queue_waiter {
|
||||
int max_packets; // Максимальное количество пакетов
|
||||
size_t max_bytes; // Максимальное количество байт
|
||||
void (*callback)(struct ll_queue* q, void* arg); // Коллбэк для вызова
|
||||
void* callback_arg; // Аргумент коллбэка
|
||||
struct queue_waiter* next; // Следующий ожидающий в списке
|
||||
};
|
||||
|
||||
typedef void (*queue_threshold_callback_fn)(struct ll_queue* q, void* arg);
|
||||
|
||||
// Структура очереди
|
||||
struct ll_queue {
|
||||
struct ll_entry* head; // Первый элемент (извлекается отсюда)
|
||||
struct ll_entry* tail; // Последний элемент (добавляется сюда)
|
||||
int count; // Текущее количество элементов
|
||||
size_t total_bytes; // Общий размер данных всех элементов (байт)
|
||||
int size_limit; // Максимальное количество (-1 = без ограничения)
|
||||
|
||||
queue_callback_fn callback; // Функция коллбэка
|
||||
void* callback_arg; // Пользовательский аргумент для коллбэка
|
||||
int callback_suspended; // 1 если коллбэки приостановлены (во время обработки)
|
||||
|
||||
void* resume_timeout_id; // ID таймаута uasync для отложенного возобновления
|
||||
struct UASYNC* ua; // Экземпляр uasync для таймеров
|
||||
|
||||
struct queue_waiter* waiters; // Список ожидающих коллбэков
|
||||
|
||||
// Пулы памяти для оптимизации аллокаций
|
||||
struct memory_pool* pool; // Пул для структур struct queue_waiter
|
||||
};
|
||||
|
||||
// ==================== Управление очередью ====================
|
||||
|
||||
// Создать новую пустую очередь
|
||||
// ua - экземпляр uasync для таймеров (обязательный параметр)
|
||||
// pool - если не null то использовать этот пул памяти
|
||||
// Возвращает: указатель на очередь или NULL при ошибке выделения памяти (see memory_pool.c/h)
|
||||
struct ll_queue* queue_new(struct UASYNC* ua, struct memory_pool* pool);
|
||||
|
||||
// Освободить очередь и все её элементы
|
||||
// Также отменяет отложенное возобновление если оно запланировано
|
||||
void queue_free(struct ll_queue* q);
|
||||
|
||||
// ==================== Конфигурация очереди ====================
|
||||
|
||||
// Установить функцию и аргумент коллбэка для автозабора из очереди
|
||||
// Коллбэк вызывается когда в очереди есть элемент и разрешен коллбэк
|
||||
// обработчик должен обработать этот пакет (может использовать асинхронное ожидание). Когда будет готов к приёму следующего - должен вызвать resume_callback. обработка строго по одному пакету.
|
||||
void queue_set_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg);
|
||||
|
||||
// Возобновить коллбэки после обработки элемента переданного в коллбэке (тянуть дополнительные элементы из очереди не предусмотернные api нельзя).
|
||||
// эта функция должна вызываться всегда после того как cbk_fn обработала пакет (можно с ожиданием через async), иначе очередь застрянет.
|
||||
// Если в очереди остались элементы, запланирует вызов коллбэка через uasync_set_timeout(0)
|
||||
// Это предотвращает накопление рекурсии в стеке вызовов
|
||||
void queue_resume_callback(struct ll_queue* q);
|
||||
|
||||
// Установить максимальное количество элементов в очереди
|
||||
// При превышении лимита новый элемент автоматически освобождается
|
||||
void queue_set_size_limit(struct ll_queue* q, int lim);
|
||||
|
||||
// ==================== Управление элементами ====================
|
||||
|
||||
// Создать новый элемент с областью данных указанного размера
|
||||
// Память выделяется одним блоком: [struct ll_entry][область данных data_size байт]
|
||||
// Возвращает: указатель на элемент или NULL при ошибке выделения памяти
|
||||
struct ll_entry* queue_entry_new(size_t data_size);
|
||||
|
||||
// Освободить элемент (не влияет на связи в очереди)
|
||||
void queue_entry_free(struct ll_entry* entry);
|
||||
|
||||
// ==================== Операции с очередью ====================
|
||||
|
||||
// Добавить элемент в конец очереди (FIFO)
|
||||
// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк
|
||||
// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден)
|
||||
int queue_entry_put(struct ll_queue* q, struct ll_entry* entry);
|
||||
|
||||
// Добавить элемент в начало очереди (LIFO, высокий приоритет)
|
||||
// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк
|
||||
// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден)
|
||||
int queue_entry_put_first(struct ll_queue* q, struct ll_entry* entry);
|
||||
|
||||
// Извлечь элемент из начала очереди
|
||||
// При извлечении приостанавливает коллбэки (callback_suspended = 1) чтобы предотвратить рекурсию
|
||||
// Возвращает: указатель на элемент или NULL если очередь пуста
|
||||
struct ll_entry* queue_entry_get(struct ll_queue* q);
|
||||
|
||||
// Получить текущее количество элементов в очереди
|
||||
int queue_entry_count(struct ll_queue* q);
|
||||
|
||||
// ==================== Вспомогательные функции ====================
|
||||
|
||||
// Получить указатель на область данных элемента
|
||||
// Данные расположены сразу после структуры struct ll_entry
|
||||
static inline void* ll_entry_data(struct ll_entry* entry) {
|
||||
return (void*)(entry + 1);
|
||||
}
|
||||
|
||||
// Получить размер данных элемента
|
||||
static inline size_t ll_entry_size(struct ll_entry* entry) {
|
||||
return entry->size;
|
||||
}
|
||||
|
||||
// ==================== Асинхронное ожидание ====================
|
||||
|
||||
// Зарегистрировать одноразовый коллбэк, который будет вызван когда очередь будет иметь
|
||||
// не более max_packets пакетов и не более max_bytes байт.
|
||||
// Если условие уже выполнено, коллбэк вызывается немедленно.
|
||||
// Можно зарегистрировать несколько ожиданий на одной очереди.
|
||||
// Возвращает указатель на waiter для возможной отмены через queue_cancel_wait
|
||||
struct queue_waiter* queue_wait_threshold(struct ll_queue* q, int max_packets, size_t max_bytes,
|
||||
queue_threshold_callback_fn callback, void* arg);
|
||||
|
||||
// Отменить ожидание (удалить waiter из списка)
|
||||
void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter);
|
||||
|
||||
// Получить общий размер данных в очереди (байт)
|
||||
static inline size_t queue_total_bytes(struct ll_queue* q) {
|
||||
if (!q) return 0;
|
||||
return q->total_bytes;
|
||||
}
|
||||
|
||||
// Получить статистику использования пулов памяти
|
||||
void queue_get_pool_stats(struct ll_queue* q, size_t* waiter_allocations, size_t* waiter_reuse);
|
||||
|
||||
#endif // LL_QUEUE_H
|
||||
Reference in new issue
Block a user