// memory_pool.c #include #include #include #include "memory_pool.h" #include "mem.h" // Layout: [user_data: object_size] [canary: 4 bytes] [alloc_loc: pointer] [counter: 1 byte] #define POOL_CANARY_OFF (pool->object_size) #define POOL_LOC_OFF (pool->object_size + 4) #define POOL_COUNTER_OFF (pool->object_size + 4 + sizeof(const char*)) #define POOL_ALLOC_SIZE (pool->object_size + 4 + sizeof(const char*) + 1) #define POOL_CANARY_VAL 0xDEADBEAF static void pool_init_tags(struct memory_pool* pool, void* obj, const char* location) { uint32_t* canary = (uint32_t*)((uint8_t*)obj + POOL_CANARY_OFF); const char** loc = (const char**)((uint8_t*)obj + POOL_LOC_OFF); uint8_t* counter = (uint8_t*)obj + POOL_COUNTER_OFF; *canary = POOL_CANARY_VAL; *loc = location; *counter = 1; } static void pool_check_and_clear_tags(struct memory_pool* pool, void* obj, const char* location) { uint32_t* canary = (uint32_t*)((uint8_t*)obj + POOL_CANARY_OFF); const char** loc = (const char**)((uint8_t*)obj + POOL_LOC_OFF); uint8_t* counter = (uint8_t*)obj + POOL_COUNTER_OFF; if (*canary != POOL_CANARY_VAL) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free BUFFER OVERFLOW pool=%p name=%s sz=%zu allocs=%zu reuse=%zu free=%d", pool, pool->name ? pool->name : "?", pool->object_size, pool->allocations, pool->reuse_count, pool->free_count); DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " obj=%p alloc=%s free=%s canary=0x%08x expected=0x%08x", obj, *loc ? *loc : "(null)", location, *canary, POOL_CANARY_VAL); if (pool->object_size) log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_MEMORY, " user_data", obj, pool->object_size); volatile int _halt = 1; while (_halt) {} } if (*counter == 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free DOUBLE FREE pool=%p name=%s sz=%zu allocs=%zu reuse=%zu alloc=%s free=%s", pool, pool->name ? pool->name : "?", pool->object_size, pool->allocations, pool->reuse_count, *loc ? *loc : "(null)", 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, const char* name) { 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; pool->name = name; 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, location); DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "pool_alloc reused: %s, remaining=%zu", location, pool->free_count); return obj; } pool->allocations++; DEBUG_DEBUG(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, location); 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_DEBUG(DEBUG_CATEGORY_MEMORY, "pool_free returned: %s, free_count=%zu", location, pool->free_count); return; } DEBUG_DEBUG(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; } void* obj = pool->free_head; while (obj) { void* next = *(void**)obj; g_total_free--; u_free(obj); obj = next; } 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; }