mem
This commit is contained in:
1 parent
b2640e7201
commit
15c7968c8c
34 files changed
+332
-284
No files matched your search
+3
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user