// memory_pool.c #include #include #include #include "memory_pool.h" #include "mem.h" #define POOL_CANARY_OFF (pool->object_size) #define POOL_TAG_OFF (pool->object_size + 1) #define POOL_ALLOC_SIZE (pool->object_size + 2) #define POOL_CANARY_VAL 0xAA static void pool_init_tags(struct memory_pool* pool, void* obj) { uint8_t* canary = (uint8_t*)obj + POOL_CANARY_OFF; uint8_t* counter = (uint8_t*)obj + POOL_TAG_OFF; *canary = POOL_CANARY_VAL; *counter = 1; } static void pool_check_and_clear_tags(struct memory_pool* pool, void* obj, const char* location) { uint8_t* canary = (uint8_t*)obj + POOL_CANARY_OFF; uint8_t* counter = (uint8_t*)obj + POOL_TAG_OFF; if (*canary != POOL_CANARY_VAL) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free BUFFER OVERFLOW %p canary=0x%02x from %s! halting", obj, *canary, location); volatile int _halt = 1; while (_halt) {} } if (*counter == 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free DOUBLE FREE %p from %s! halting", obj, location); volatile int _halt = 1; while (_halt) {} } *counter = 0; } static size_t g_total_free = 0; size_t memory_pool_get_total_free_blocks(void) { return g_total_free; } // Инициализировать пул памяти struct memory_pool* memory_pool_init(size_t object_size) { struct memory_pool* pool = u_calloc(1, sizeof(struct memory_pool)); if (!pool) { return NULL; } pool->free_head = NULL; pool->object_size = object_size; pool->free_count = 0; pool->allocations = 0; pool->reuse_count = 0; pool->alloc_tag_counter = 1; return pool; } // Выделить объект из пула или из malloc void* memory_pool_alloc_impl(struct memory_pool* pool, const char* location) { if (!pool) { return NULL; } if (pool->free_head) { void* obj = pool->free_head; pool->free_head = *(void**)obj; pool->free_count--; g_total_free--; pool->reuse_count++; memset(obj, 0, pool->object_size); pool_init_tags(pool, obj); DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "pool_alloc reused: %s, remaining=%zu", location, pool->free_count); return obj; } pool->allocations++; DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "pool_alloc: %s, total_allocs=%zu", location, pool->allocations); void* obj = u_calloc_impl(1, POOL_ALLOC_SIZE, location); if (obj) pool_init_tags(pool, obj); return obj; } // Освободить объект в пул или в free void memory_pool_free_impl(struct memory_pool* pool, void* obj, const char* location) { if (!pool || !obj) { return; } pool_check_and_clear_tags(pool, obj, location); if (pool->free_count < MEMORY_POOL_MAX_FREE) { *(void**)obj = pool->free_head; pool->free_head = obj; pool->free_count++; g_total_free++; DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "pool_free returned: %s, free_count=%zu", location, pool->free_count); return; } DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "pool_free direct: %s", location); u_free_impl(obj, location); } // Получить статистику пула void memory_pool_get_stats(struct memory_pool* pool, size_t* allocations, size_t* reuse_count) { if (!pool) { return; } if (allocations) { *allocations = pool->allocations; } if (reuse_count) { *reuse_count = pool->reuse_count; } } // Очистить пул памяти void memory_pool_destroy(struct memory_pool* pool) { if (!pool) { return; } int cnt=0; // Освободить все объекты в пуле void* obj = pool->free_head; while (obj) { void* next = *(void**)obj; g_total_free--; u_free(obj); cnt++; obj = next; } // if (cnt>MEMORY_POOL_MAX_FREE) DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_destroy: allocations=%zu, reuse=%zu, current pool size=%d", pool->allocations, pool->reuse_count, cnt); pool->free_head = NULL; pool->free_count = 0; u_free(pool); } int memory_pool_is_freed(struct memory_pool* pool, void* obj) { if (!pool || !obj) return 0; void* cur = pool->free_head; while (cur) { if (cur == obj) return 1; cur = *(void**)cur; } return 0; }