This commit is contained in:
jeka committed 2026-03-06 01:36:57 +03:00
1 parent b2640e7201
commit 15c7968c8c
34 files changed
+332 -284

No files matched your search

+3 -1
View File
@@ -16,7 +16,9 @@ libuasync_a_SOURCES = \
socket_compat.c \
socket_compat.h \
platform_compat.c \
platform_compat.h
platform_compat.h \
mem.c \
mem.h
libuasync_a_CFLAGS = \
-D_ISOC99_SOURCE \
+6 -5
View File
@@ -4,6 +4,7 @@
#include "debug_config.h"
#include "platform_compat.h"
#include "mem.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -349,7 +350,7 @@ int debug_parse_config(const char* config_string) {
char* eq = strchr(token, '=');
if (!eq) {
free(str);
u_free(str);
return -1;
}
@@ -372,7 +373,7 @@ int debug_parse_config(const char* config_string) {
debug_category_t cat = get_category_by_name(mod_token);
if (cat == DEBUG_CATEGORY_NONE) {
free(str);
u_free(str);
return -1;
}
categories |= cat;
@@ -381,12 +382,12 @@ int debug_parse_config(const char* config_string) {
} else if (strcasecmp(key, "level") == 0) {
int lev_num = atoi(value);
if (lev_num < DEBUG_LEVEL_NONE || lev_num > DEBUG_LEVEL_TRACE) {
free(str);
u_free(str);
return -1;
}
level = (debug_level_t)lev_num;
} else {
free(str);
u_free(str);
return -1;
}
@@ -395,6 +396,6 @@ int debug_parse_config(const char* config_string) {
debug_set_masks(categories, level);
free(str);
u_free(str);
return 0;
}
+13 -12
View File
@@ -6,6 +6,7 @@
#include "ll_queue.h"
#include "u_async.h"
#include "debug_config.h"
#include "mem.h"
// Предварительные объявления внутренних функций
static void queue_resume_timeout_cb(void* arg);
@@ -18,7 +19,7 @@ static void remove_from_hash(struct ll_queue* q, struct ll_entry* entry);
struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size) {
if (!ua) return NULL;
struct ll_queue* q = calloc(1, sizeof(struct ll_queue));
struct ll_queue* q = u_calloc(1, sizeof(struct ll_queue));
if (!q) return NULL;
q->ua = ua;
@@ -27,9 +28,9 @@ struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size) {
// Создать хеш-таблицу если нужно
if (hash_size > 0) {
q->hash_table = calloc(hash_size, sizeof(struct ll_entry*));
q->hash_table = u_calloc(hash_size, sizeof(struct ll_entry*));
if (!q->hash_table) {
free(q);
u_free(q);
return NULL;
}
}
@@ -45,7 +46,7 @@ struct ll_entry* ll_alloc_lldgram(uint16_t len) {
entry->len=0;
entry->memlen=len;
entry->dgram = malloc(len);
entry->dgram = u_malloc(len);
// entry->dgram_pool = NULL; - уже null (memset)
// entry->dgram_free_fn = NULL;
if (!entry->dgram) {
@@ -63,11 +64,11 @@ void queue_free(struct ll_queue* q) {
q, q->head, q->tail, q->count);
// ВАЖНО: Не освобождаем элементы в очереди - они должны быть извлечены отдельно
// Это упрощает архитектуру и предотвращает double-free
// Это упрощает архитектуру и предотвращает double-u_free
// Освободить хеш-таблицу
if (q->hash_table) {
free(q->hash_table);
u_free(q->hash_table);
}
// Отменить отложенное возобновление
@@ -76,7 +77,7 @@ void queue_free(struct ll_queue* q) {
q->resume_timeout_id = NULL;
}
free(q);
u_free(q);
}
// ==================== Конфигурация очереди ====================
@@ -118,13 +119,13 @@ void queue_set_size_limit(struct ll_queue* q, int lim) {
// ==================== Управление элементами ====================
struct ll_entry* queue_entry_new(size_t data_size) {
struct ll_entry* entry = malloc(sizeof(struct ll_entry) + data_size);
struct ll_entry* entry = u_malloc(sizeof(struct ll_entry) + data_size);
if (!entry) return NULL;
memset(entry, 0, sizeof(struct ll_entry) + data_size);
entry->size = data_size;
entry->len = 0;
entry->pool = NULL; // Выделено через malloc
entry->pool = NULL; // Выделено через u_malloc
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new: created entry %p, size=%zu", entry, data_size);
@@ -147,7 +148,7 @@ struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool) {
return entry;
}
//void ll_free_dgram(struct ll_entry* entry) {
//void ll_u_free_dgram(struct ll_entry* entry) {
void queue_dgram_free(struct ll_entry* entry) {
if (!entry) return;
@@ -157,7 +158,7 @@ void queue_dgram_free(struct ll_entry* entry) {
} else if (entry->dgram_pool) {
memory_pool_free(entry->dgram_pool, entry->dgram);
} else {
free(entry->dgram);
u_free(entry->dgram);
}
entry->dgram = NULL;
entry->len = 0; // Опционально сброс len
@@ -170,7 +171,7 @@ void queue_entry_free(struct ll_entry* entry) {
if (entry->pool) {
memory_pool_free(entry->pool, entry);
} else {
free(entry);
u_free(entry);
}
}
+6 -5
View File
@@ -2,10 +2,11 @@
#include "memory_pool.h"
#include <stdlib.h>
#include <string.h>
#include "mem.h"
// Инициализировать пул памяти
struct memory_pool* memory_pool_init(size_t object_size) {
struct memory_pool* pool = calloc(1, sizeof(struct memory_pool));
struct memory_pool* pool = u_calloc(1, sizeof(struct memory_pool));
if (!pool) {
return NULL;
}
@@ -33,7 +34,7 @@ void* memory_pool_alloc(struct memory_pool* pool) {
}
pool->allocations++;
return calloc(1, pool->object_size); // Используем calloc для инициализации нулями
return u_calloc(1, pool->object_size); // Используем calloc для инициализации нулями
}
// Освободить объект в пул или в free
@@ -51,7 +52,7 @@ void memory_pool_free(struct memory_pool* pool, void* obj) {
}
// Иначе освободить через free
free(obj);
u_free(obj);
}
// Получить статистику пула
@@ -77,11 +78,11 @@ void memory_pool_destroy(struct memory_pool* pool) {
void* obj = pool->free_head;
while (obj) {
void* next = *(void**)obj;
free(obj);
u_free(obj);
obj = next;
}
pool->free_head = NULL;
pool->free_count = 0;
free(pool);
u_free(pool);
}
+6 -6
View File
@@ -11,11 +11,11 @@
#define RIGHT_CHILD(i) (2 * (i) + 1)
TimeoutHeap *timeout_heap_create(size_t initial_capacity) {
TimeoutHeap *h = malloc(sizeof(TimeoutHeap));
TimeoutHeap *h = u_malloc(sizeof(TimeoutHeap));
if (!h) return NULL;
h->heap = malloc(sizeof(TimeoutEntry) * initial_capacity);
h->heap = u_malloc(sizeof(TimeoutEntry) * initial_capacity);
if (!h->heap) {
free(h);
u_free(h);
return NULL;
}
h->size = 0;
@@ -37,8 +37,8 @@ void timeout_heap_destroy(TimeoutHeap *h) {
}
}
free(h->heap);
free(h);
u_free(h->heap);
u_free(h);
}
@@ -56,7 +56,7 @@ static void bubble_up(TimeoutHeap *h, size_t i) {
int timeout_heap_push(TimeoutHeap *h, TimeoutTime expiration, void *data) {
if (h->size == h->capacity) {
size_t new_cap = h->capacity ? h->capacity * 2 : 1;
TimeoutEntry *new_heap = realloc(h->heap, sizeof(TimeoutEntry) * new_cap);
TimeoutEntry *new_heap = u_realloc(h->heap, sizeof(TimeoutEntry) * new_cap);
if (!new_heap) return -1; // Allocation failed
h->heap = new_heap;
h->capacity = new_cap;
+78 -68
View File
@@ -3,6 +3,7 @@
#include "u_async.h"
#include "platform_compat.h"
#include "debug_config.h"
#include "mem.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -46,7 +47,7 @@ struct socket_node {
socket_t_callback_t write_cbk_sock; // For SOCK type
socket_callback_t except_cbk;
void* user_data;
int active; // 1 if socket is active, 0 if freed (for reuse)
int active; // 1 if socket is active, 0 if u_freed (for reuse)
};
// Array-based socket management for O(1) operations
@@ -72,20 +73,20 @@ static struct socket_node* socket_array_get(struct socket_array* sa, int fd);
static struct socket_array* socket_array_create(int initial_capacity) {
if (initial_capacity < 4) initial_capacity = 4; // Minimum capacity
struct socket_array* sa = malloc(sizeof(struct socket_array));
struct socket_array* sa = u_malloc(sizeof(struct socket_array));
if (!sa) return NULL;
sa->sockets = calloc(initial_capacity, sizeof(struct socket_node));
sa->fd_to_index = calloc(initial_capacity, sizeof(int));
sa->index_to_fd = calloc(initial_capacity, sizeof(int));
sa->active_indices = calloc(initial_capacity, sizeof(int));
sa->sockets = u_calloc(initial_capacity, sizeof(struct socket_node));
sa->fd_to_index = u_calloc(initial_capacity, sizeof(int));
sa->index_to_fd = u_calloc(initial_capacity, sizeof(int));
sa->active_indices = u_calloc(initial_capacity, sizeof(int));
if (!sa->sockets || !sa->fd_to_index || !sa->index_to_fd || !sa->active_indices) {
free(sa->sockets);
free(sa->fd_to_index);
free(sa->index_to_fd);
free(sa->active_indices);
free(sa);
u_free(sa->sockets);
u_free(sa->fd_to_index);
u_free(sa->index_to_fd);
u_free(sa->active_indices);
u_free(sa);
return NULL;
}
@@ -108,11 +109,11 @@ static struct socket_array* socket_array_create(int initial_capacity) {
static void socket_array_destroy(struct socket_array* sa) {
if (!sa) return;
free(sa->sockets);
free(sa->fd_to_index);
free(sa->index_to_fd);
free(sa->active_indices);
free(sa);
u_free(sa->sockets);
u_free(sa->fd_to_index);
u_free(sa->index_to_fd);
u_free(sa->active_indices);
u_free(sa);
}
static int socket_array_add_internal(struct socket_array* sa, int fd, socket_t sock, int type,
@@ -129,17 +130,17 @@ static int socket_array_add_internal(struct socket_array* sa, int fd, socket_t s
int new_capacity = sa->capacity * 2;
if (fd >= new_capacity) new_capacity = fd + 16; // Ensure enough space
struct socket_node* new_sockets = realloc(sa->sockets, new_capacity * sizeof(struct socket_node));
int* new_fd_to_index = realloc(sa->fd_to_index, new_capacity * sizeof(int));
int* new_index_to_fd = realloc(sa->index_to_fd, new_capacity * sizeof(int));
int* new_active_indices = realloc(sa->active_indices, new_capacity * sizeof(int));
struct socket_node* new_sockets = u_realloc(sa->sockets, new_capacity * sizeof(struct socket_node));
int* new_fd_to_index = u_realloc(sa->fd_to_index, new_capacity * sizeof(int));
int* new_index_to_fd = u_realloc(sa->index_to_fd, new_capacity * sizeof(int));
int* new_active_indices = u_realloc(sa->active_indices, new_capacity * sizeof(int));
if (!new_sockets || !new_fd_to_index || !new_index_to_fd || !new_active_indices) {
// Allocation failed
free(new_sockets);
free(new_fd_to_index);
free(new_index_to_fd);
free(new_active_indices);
u_free(new_sockets);
u_free(new_fd_to_index);
u_free(new_index_to_fd);
u_free(new_active_indices);
return -1;
}
@@ -162,7 +163,7 @@ static int socket_array_add_internal(struct socket_array* sa, int fd, socket_t s
// Check if FD already exists
if (sa->fd_to_index[fd] != -1) return -1; // FD already exists
// Find first free slot
// Find first u_free slot
int index = -1;
for (int i = 0; i < sa->capacity; i++) {
if (!sa->sockets[i].active) {
@@ -171,7 +172,7 @@ static int socket_array_add_internal(struct socket_array* sa, int fd, socket_t s
}
}
if (index == -1) return -1; // No free slots (shouldn't happen)
if (index == -1) return -1; // No u_free slots (shouldn't happen)
// Add the socket
sa->sockets[index].fd = fd;
@@ -272,13 +273,13 @@ static struct socket_node* socket_array_get_by_sock(struct socket_array* sa, soc
return &sa->sockets[index];
}
// Callback to free timeout node and update counters
// Callback to u_free timeout node and update counters
static void timeout_node_free_callback(void* user_data, void* data) {
struct UASYNC* ua = (struct UASYNC*)user_data;
struct timeout_node* node = (struct timeout_node*)data;
(void)node; // Not used directly, but keep for consistency
ua->timer_free_count++;
free(data);
u_free(data);
}
// Helper to get current time
@@ -329,19 +330,20 @@ static void drain_wakeup_pipe(struct UASYNC* ua) {
}
}
// Process posted tasks (lock-free during execution)
// Process posted tasks (lock-u_free during execution)
static void process_posted_tasks(struct UASYNC* ua) {
if (!ua) return;
struct posted_task* list = NULL;
#ifdef _WIN32
EnterCriticalSection(&ua->posted_lock);
#else
pthread_mutex_lock(&ua->posted_lock);
#endif
list = ua->posted_tasks_head;
ua->posted_tasks_head = NULL;
ua->posted_tasks_head = ua->posted_tasks_tail = NULL;
#ifdef _WIN32
LeaveCriticalSection(&ua->posted_lock);
#else
@@ -349,13 +351,14 @@ static void process_posted_tasks(struct UASYNC* ua) {
#endif
while (list) {
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "POSTed task get");
struct posted_task* t = list;
list = list->next;
if (t->callback) {
t->callback(t->arg);
}
free(t);
u_free(t);
}
}
@@ -417,11 +420,11 @@ static void process_timeouts(struct UASYNC* ua) {
node->callback(node->arg);
}
// Always free the node after processing
// Always u_free the node after processing
if (node && node->ua) {
node->ua->timer_free_count++;
}
free(node);
u_free(node);
continue; // Process next expired timeout
}
}
@@ -465,7 +468,7 @@ void* uasync_set_timeout(struct UASYNC* ua, int timeout_tb, void* arg, timeout_c
// DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "uasync_set_timeout: timeout=%d.%d ms, arg=%p, callback=%p", timeout_tb/10, timeout_tb%10, arg, callback);
struct timeout_node* node = malloc(sizeof(struct timeout_node));
struct timeout_node* node = u_malloc(sizeof(struct timeout_node));
if (!node) {
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "uasync_set_timeout: failed to allocate node");
return NULL;
@@ -486,7 +489,7 @@ void* uasync_set_timeout(struct UASYNC* ua, int timeout_tb, void* arg, timeout_c
// Add to heap
if (timeout_heap_push(ua->timeout_heap, node->expiration_ms, node) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "uasync_set_timeout: failed to push to heap");
free(node);
u_free(node);
ua->timer_free_count++; // Balance the alloc counter
return NULL;
}
@@ -508,7 +511,7 @@ err_t uasync_cancel_timeout(struct UASYNC* ua, void* t_id) {
// Try to cancel from heap first
if (timeout_heap_cancel(ua->timeout_heap, node->expiration_ms, node) == 0) {
// Successfully marked as deleted - free will happen lazily in heap
// Successfully marked as deleted - u_free will happen lazily in heap
node->cancelled = 1;
node->callback = NULL;
// DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "uasync_cancel_timeout: successfully cancelled timer %p from heap", node);
@@ -666,7 +669,7 @@ static void rebuild_poll_fds(struct UASYNC* ua) {
int new_capacity = total_fds * 2;
if (new_capacity < 16) new_capacity = 16;
struct pollfd* new_poll_fds = realloc(ua->poll_fds, sizeof(struct pollfd) * new_capacity);
struct pollfd* new_poll_fds = u_realloc(ua->poll_fds, sizeof(struct pollfd) * new_capacity);
if (!new_poll_fds) return; // Keep old allocation on failure
ua->poll_fds = new_poll_fds;
@@ -1091,7 +1094,7 @@ struct UASYNC* uasync_create(void) {
// Initialize socket platform (Winsock on Windows)
socket_platform_init();
struct UASYNC* ua = calloc(1, sizeof(struct UASYNC));
struct UASYNC* ua = u_calloc(1, sizeof(struct UASYNC));
if (!ua) return NULL;
ua->timer_alloc_count = 0;
@@ -1120,7 +1123,7 @@ struct UASYNC* uasync_create(void) {
close(ua->wakeup_pipe[1]);
#endif
}
free(ua);
u_free(ua);
return NULL;
}
@@ -1136,11 +1139,11 @@ struct UASYNC* uasync_create(void) {
close(ua->wakeup_pipe[1]);
#endif
}
free(ua);
u_free(ua);
return NULL;
}
// Set callback to free timeout nodes and update counters
// Set callback to u_free timeout nodes and update counters
timeout_heap_set_free_callback(ua->timeout_heap, ua, timeout_node_free_callback);
// Initialize epoll on Linux
@@ -1171,7 +1174,7 @@ struct UASYNC* uasync_create(void) {
SOCKET w = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r == INVALID_SOCKET || w == INVALID_SOCKET) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "Failed to create wakeup sockets");
free(ua);
u_free(ua);
return NULL;
}
@@ -1186,7 +1189,7 @@ struct UASYNC* uasync_create(void) {
closesocket(r);
closesocket(w);
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "Wakeup socket setup failed: %d", WSAGetLastError());
free(ua);
u_free(ua);
return NULL;
}
@@ -1206,7 +1209,7 @@ struct UASYNC* uasync_create(void) {
// POSIX pipe
if (pipe(ua->wakeup_pipe) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "pipe() failed: %s", strerror(errno));
free(ua);
u_free(ua);
return NULL;
}
ua->wakeup_initialized = 1;
@@ -1232,10 +1235,10 @@ void uasync_print_resources(struct UASYNC* ua, const char* prefix) {
}
printf("\n🔍 %s: UASYNC Resource Report for %p\n", prefix, ua);
printf(" Timer Statistics: allocated=%zu, freed=%zu, active=%zd\n",
printf(" Timer Statistics: allocated=%zu, u_freed=%zu, active=%zd\n",
ua->timer_alloc_count, ua->timer_free_count,
(ssize_t)(ua->timer_alloc_count - ua->timer_free_count));
printf(" Socket Statistics: allocated=%zu, freed=%zu, active=%zd\n",
printf(" Socket Statistics: allocated=%zu, u_freed=%zu, active=%zd\n",
ua->socket_alloc_count, ua->socket_free_count,
(ssize_t)(ua->socket_alloc_count - ua->socket_free_count));
@@ -1288,10 +1291,10 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
if (ua->timer_alloc_count != ua->timer_free_count || ua->socket_alloc_count != ua->socket_free_count) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Memory leaks detected before cleanup: timers %zu/%zu, sockets %zu/%zu",
ua->timer_alloc_count, ua->timer_free_count, ua->socket_alloc_count, ua->socket_free_count);
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "Timer leak: allocated=%zu, freed=%zu, diff=%zd",
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "Timer leak: allocated=%zu, u_freed=%zu, diff=%zd",
ua->timer_alloc_count, ua->timer_free_count,
(ssize_t)(ua->timer_alloc_count - ua->timer_free_count));
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "Socket leak: allocated=%zu, freed=%zu, diff=%zd",
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "Socket leak: allocated=%zu, u_freed=%zu, diff=%zd",
ua->socket_alloc_count, ua->socket_free_count,
(ssize_t)(ua->socket_alloc_count - ua->socket_free_count));
// Continue cleanup, will abort after if leaks remain
@@ -1299,16 +1302,16 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
// Free all remaining timeouts
if (ua->timeout_heap) {
size_t freed_count = 0;
size_t u_freed_count = 0;
while (1) {
TimeoutEntry entry;
if (timeout_heap_pop(ua->timeout_heap, &entry) != 0) break;
struct timeout_node* node = (struct timeout_node*)entry.data;
// Free all timer nodes (avoid double-free bug)
// Free all timer nodes (avoid double-u_free bug)
if (node) {
ua->timer_free_count++;
free(node);
u_free(node);
}
}
timeout_heap_destroy(ua->timeout_heap);
@@ -1316,8 +1319,8 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
// Free all socket nodes using array approach
if (ua->sockets) {
// Count and free all active sockets
int freed_count = 0;
// Count and u_free all active sockets
int u_freed_count = 0;
for (int i = 0; i < ua->sockets->capacity; i++) {
if (ua->sockets->sockets[i].active) {
if (close_fds && ua->sockets->sockets[i].fd >= 0) {
@@ -1332,10 +1335,10 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
#endif
}
ua->socket_free_count++;
freed_count++;
u_freed_count++;
}
}
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "Freed %d socket nodes in destroy", freed_count);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "Freed %d socket nodes in destroy", u_freed_count);
socket_array_destroy(ua->sockets);
}
@@ -1351,7 +1354,7 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
}
// Free cached poll_fds
free(ua->poll_fds);
u_free(ua->poll_fds);
// Close epoll fd on Linux
#if HAS_EPOLL
@@ -1364,10 +1367,10 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
if (ua->timer_alloc_count != ua->timer_free_count || ua->socket_alloc_count != ua->socket_free_count) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Memory leaks detected after cleanup: timers %zu/%zu, sockets %zu/%zu",
ua->timer_alloc_count, ua->timer_free_count, ua->socket_alloc_count, ua->socket_free_count);
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "FINAL Timer leak: allocated=%zu, freed=%zu, diff=%zd",
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "FINAL Timer leak: allocated=%zu, u_freed=%zu, diff=%zd",
ua->timer_alloc_count, ua->timer_free_count,
(ssize_t)(ua->timer_alloc_count - ua->timer_free_count));
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "FINAL Socket leak: allocated=%zu, freed=%zu, diff=%zd",
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "FINAL Socket leak: allocated=%zu, u_freed=%zu, diff=%zd",
ua->socket_alloc_count, ua->socket_free_count,
(ssize_t)(ua->socket_alloc_count - ua->socket_free_count));
abort();
@@ -1378,7 +1381,7 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
while (ua->posted_tasks_head) {
struct posted_task* t = ua->posted_tasks_head;
ua->posted_tasks_head = t->next;
free(t);
u_free(t);
}
#ifdef _WIN32
DeleteCriticalSection(&ua->posted_lock);
@@ -1386,7 +1389,7 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
pthread_mutex_destroy(&ua->posted_lock);
#endif
free(ua);
u_free(ua);
// Cleanup socket platform (WSACleanup on Windows)
socket_platform_cleanup();
@@ -1409,18 +1412,18 @@ void uasync_init_instance(struct UASYNC* ua) {
}
// Debug statistics
void uasync_get_stats(struct UASYNC* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free) {
void uasync_get_stats(struct UASYNC* ua, size_t* timer_alloc, size_t* timer_u_free, size_t* socket_alloc, size_t* socket_u_free) {
if (!ua) return;
if (timer_alloc) *timer_alloc = ua->timer_alloc_count;
if (timer_free) *timer_free = ua->timer_free_count;
if (timer_u_free) *timer_u_free = ua->timer_free_count;
if (socket_alloc) *socket_alloc = ua->socket_alloc_count;
if (socket_free) *socket_free = ua->socket_free_count;
if (socket_u_free) *socket_u_free = ua->socket_free_count;
}
void uasync_post(struct UASYNC* ua, uasync_post_callback_t callback, void* arg) {
if (!ua || !callback) return;
struct posted_task* task = malloc(sizeof(struct posted_task));
struct posted_task* task = u_malloc(sizeof(struct posted_task));
if (!task) return;
task->callback = callback;
@@ -1432,15 +1435,22 @@ void uasync_post(struct UASYNC* ua, uasync_post_callback_t callback, void* arg)
#else
pthread_mutex_lock(&ua->posted_lock);
#endif
task->next = ua->posted_tasks_head;
ua->posted_tasks_head = task;
if (ua->posted_tasks_tail) {
// есть конец списка — добавляем туда
ua->posted_tasks_tail->next = task;
ua->posted_tasks_tail = task;
} else {
// список пустой — это первая задача
ua->posted_tasks_head = ua->posted_tasks_tail = task;
}
#ifdef _WIN32
LeaveCriticalSection(&ua->posted_lock);
#else
pthread_mutex_unlock(&ua->posted_lock);
#endif
// DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "POST: wakeup send");
uasync_wakeup(ua); // будим mainloop
}
@@ -1466,7 +1476,7 @@ int uasync_get_wakeup_fd(struct UASYNC* ua) {
return ua->wakeup_pipe[1];
}
/* Lookup socket by file descriptor - returns current pointer even after realloc */
/* Lookup socket by file descriptor - returns current pointer even after u_realloc */
int uasync_lookup_socket(struct UASYNC* ua, int fd, void** socket_id) {
if (!ua || !ua->sockets || !socket_id || fd < 0 || fd >= FD_SETSIZE) {
return -1;
+8 -5
View File
@@ -27,6 +27,12 @@ typedef int err_t;
typedef void (*uasync_post_callback_t)(void* user_arg);
struct posted_task {
uasync_post_callback_t callback;
void* arg;
struct posted_task* next;
};
// Uasync instance structure
struct UASYNC {
TimeoutHeap* timeout_heap; // Heap for timeout management
@@ -47,11 +53,8 @@ struct UASYNC {
// Epoll support (Linux only)
int epoll_fd; // epoll file descriptor (-1 if not using epoll)
int use_epoll; // 1 if using epoll, 0 if using poll
struct posted_task {
uasync_post_callback_t callback;
void* arg;
struct posted_task* next;
} *posted_tasks_head;
struct posted_task* posted_tasks_head;
struct posted_task* posted_tasks_tail;
#ifdef _WIN32
CRITICAL_SECTION posted_lock;