|
|
|
|
@ -8,6 +8,41 @@
|
|
|
|
|
#include "debug_config.h" |
|
|
|
|
#include "mem.h" |
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
#include <windows.h> |
|
|
|
|
#else |
|
|
|
|
#include <pthread.h> |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// ==================== Thread safety check ====================
|
|
|
|
|
#ifdef QUEUE_THREAD_CHECK |
|
|
|
|
static inline void queue_check_thread(struct ll_queue* q) { |
|
|
|
|
if (!q) return; |
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
DWORD current = GetCurrentThreadId(); |
|
|
|
|
if (q->owner_thread != current) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu", |
|
|
|
|
q->name ? q->name : "unknown",
|
|
|
|
|
(unsigned long)q->owner_thread,
|
|
|
|
|
(unsigned long)current); |
|
|
|
|
printf("ERROR: Queue '%s' accessed from wrong thread!\n", q->name ? q->name : "unknown"); |
|
|
|
|
abort(); |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
pthread_t current = pthread_self(); |
|
|
|
|
if (!pthread_equal(q->owner_thread, current)) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu", |
|
|
|
|
q->name ? q->name : "unknown",
|
|
|
|
|
(unsigned long)q->owner_thread,
|
|
|
|
|
(unsigned long)current); |
|
|
|
|
printf("ERROR: Queue '%s' accessed from wrong thread!\n", q->name ? q->name : "unknown"); |
|
|
|
|
abort(); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Предварительные объявления внутренних функций
|
|
|
|
|
static void queue_resume_timeout_cb(void* arg); |
|
|
|
|
static void check_waiters(struct ll_queue* q); |
|
|
|
|
@ -27,6 +62,14 @@ struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, char* name) {
|
|
|
|
|
q->size_limit = -1; // Без ограничения по умолчанию
|
|
|
|
|
q->hash_size = hash_size; |
|
|
|
|
|
|
|
|
|
#ifdef QUEUE_THREAD_CHECK |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
q->owner_thread = GetCurrentThreadId(); |
|
|
|
|
#else |
|
|
|
|
q->owner_thread = pthread_self(); |
|
|
|
|
#endif |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Создать хеш-таблицу если нужно
|
|
|
|
|
if (hash_size > 0) { |
|
|
|
|
q->hash_table = u_calloc(hash_size, sizeof(struct ll_entry*)); |
|
|
|
|
@ -227,6 +270,12 @@ static void check_waiters(struct ll_queue* q) {
|
|
|
|
|
int queue_data_put(struct ll_queue* q, struct ll_entry* entry, uint32_t id) { |
|
|
|
|
if (!q || !entry) return -1; |
|
|
|
|
|
|
|
|
|
queue_check_thread(q); |
|
|
|
|
|
|
|
|
|
#ifdef QUEUE_DEBUG |
|
|
|
|
queue_check_consistency(q);// !!!! for debug - BEFORE callback
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
entry->id = id; |
|
|
|
|
|
|
|
|
|
// Проверить лимит размера
|
|
|
|
|
@ -278,6 +327,8 @@ int queue_data_put(struct ll_queue* q, struct ll_entry* entry, uint32_t id) {
|
|
|
|
|
int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry, uint32_t id) { |
|
|
|
|
if (!q || !entry) return -1; |
|
|
|
|
|
|
|
|
|
queue_check_thread(q); |
|
|
|
|
|
|
|
|
|
entry->id = id; |
|
|
|
|
|
|
|
|
|
// Проверить лимит размера
|
|
|
|
|
@ -330,6 +381,8 @@ int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry, uint32_t id
|
|
|
|
|
struct ll_entry* queue_data_get(struct ll_queue* q) { |
|
|
|
|
if (!q || !q->head) return NULL; |
|
|
|
|
|
|
|
|
|
queue_check_thread(q); |
|
|
|
|
|
|
|
|
|
struct ll_entry* entry = q->head; |
|
|
|
|
|
|
|
|
|
q->head = entry->next; |
|
|
|
|
@ -459,6 +512,8 @@ struct ll_entry* queue_find_data_by_id(struct ll_queue* q, uint32_t id) {
|
|
|
|
|
int queue_remove_data(struct ll_queue* q, struct ll_entry* entry) { |
|
|
|
|
if (!q || !entry) return -1; |
|
|
|
|
|
|
|
|
|
queue_check_thread(q); |
|
|
|
|
|
|
|
|
|
// Удалить из двусвязного списка
|
|
|
|
|
if (entry->prev) { |
|
|
|
|
entry->prev->next = entry->next; |
|
|
|
|
|