You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
6.0 KiB
102 lines
6.0 KiB
#ifndef LL_QUEUE_H |
|
#define LL_QUEUE_H |
|
|
|
#include <stddef.h> // для 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
|
|
|