#ifndef LL_QUEUE_H #define LL_QUEUE_H #include // для size_t // Предварительные объявления typedef struct ll_queue ll_queue_t; typedef struct ll_entry ll_entry_t; // Тип коллбэка: вызывается при добавлении элемента в пустую очередь или для продолжения обработки // Параметры: указатель на очередь, указатель на элемент (первый в очереди), пользовательский аргумент typedef void (*queue_callback_t)(ll_queue_t* q, ll_entry_t* entry, void* arg); // Структура элемента - переменный размер, данные расположены сразу после структуры struct ll_entry { struct ll_entry* next; // Указатель на следующий элемент в очереди size_t size; // Размер данных элемента (байт) }; // Структура очереди struct ll_queue { ll_entry_t* head; // Первый элемент (извлекается отсюда) ll_entry_t* tail; // Последний элемент (добавляется сюда) int count; // Текущее количество элементов int size_limit; // Максимальное количество (-1 = без ограничения) queue_callback_t callback; // Функция коллбэка void* callback_arg; // Пользовательский аргумент для коллбэка int callback_suspended; // 1 если коллбэки приостановлены (во время обработки) void* resume_timeout_id; // ID таймаута uasync для отложенного возобновления }; // ==================== Управление очередью ==================== // Создать новую пустую очередь // Возвращает: указатель на очередь или NULL при ошибке выделения памяти ll_queue_t* queue_new(void); // Освободить очередь и все её элементы // Также отменяет отложенное возобновление если оно запланировано void queue_free(ll_queue_t* q); // ==================== Конфигурация очереди ==================== // Установить функцию и аргумент коллбэка для очереди // Коллбэк вызывается при добавлении элемента в пустую очередь (разрешенные коллбэки) void queue_set_callback(ll_queue_t* q, queue_callback_t cbk_fn, void* arg); // Возобновить коллбэки после обработки элемента // Если в очереди остались элементы, запланирует вызов коллбэка через uasync_set_timeout(0) // Это предотвращает накопление рекурсии в стеке вызовов void queue_resume_callback(ll_queue_t* q); // Установить максимальное количество элементов в очереди // При превышении лимита новый элемент автоматически освобождается void queue_set_size_limit(ll_queue_t* q, int lim); // ==================== Управление элементами ==================== // Создать новый элемент с областью данных указанного размера // Память выделяется одним блоком: [ll_entry_t][область данных data_size байт] // Возвращает: указатель на элемент или NULL при ошибке выделения памяти ll_entry_t* queue_entry_new(size_t data_size); // Освободить элемент (не влияет на связи в очереди) void queue_entry_free(ll_entry_t* entry); // ==================== Операции с очередью ==================== // Добавить элемент в конец очереди (FIFO) // Если очередь была пустой и коллбэки разрешены - вызывает коллбэк // Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) int queue_entry_put(ll_queue_t* q, ll_entry_t* entry); // Добавить элемент в начало очереди (LIFO, высокий приоритет) // Если очередь была пустой и коллбэки разрешены - вызывает коллбэк // Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) int queue_entry_put_first(ll_queue_t* q, ll_entry_t* entry); // Извлечь элемент из начала очереди // При извлечении приостанавливает коллбэки (callback_suspended = 1) чтобы предотвратить рекурсию // Возвращает: указатель на элемент или NULL если очередь пуста ll_entry_t* queue_entry_get(ll_queue_t* q); // Получить текущее количество элементов в очереди int queue_entry_count(ll_queue_t* q); // ==================== Вспомогательные функции ==================== // Получить указатель на область данных элемента // Данные расположены сразу после структуры ll_entry_t static inline void* ll_entry_data(ll_entry_t* entry) { return (void*)(entry + 1); } // Получить размер данных элемента static inline size_t ll_entry_size(ll_entry_t* entry) { return entry->size; } #endif // LL_QUEUE_H