void slab_free(void* ptr) { // Null pointer check if (knot_unlikely(!ptr)) { return; } // Get slab start address slab_t* slab = slab_from_ptr(ptr); assert(slab); // Check if it exists in directory if (slab->magic == SLAB_MAGIC) { // Return buf to slab *((void**)ptr) = (void*)slab->head; slab->head = (void**)ptr; ++slab->bufs_free; #ifdef MEM_DEBUG // Increment statistics __sync_add_and_fetch(&slab->cache->stat_frees, 1); #endif // Return to partial if(knot_unlikely(slab->bufs_free == 1)) { slab_list_move(&slab->cache->slabs_free, slab); } else { #ifdef MEM_SLAB_CAP // Recycle if empty if(knot_unlikely(slab_isempty(slab))) { if(slab->cache->empty == MEM_SLAB_CAP) { slab_destroy(&slab); } else { ++slab->cache->empty; } } #endif } } else { // Pointer is not a slab // Presuming it's a large block slab_obj_t* bs = (slab_obj_t*)ptr - 1; #ifdef MEM_POISON // Remove memory barrier mprotect(ptr + bs->size, sizeof(int), PROT_READ|PROT_WRITE); #endif // Unmap dbg_mem("%s: unmapping large block of %zu bytes at %p\n", __func__, bs->size, ptr); free(bs); } }
int slab_cache_reap(slab_cache_t* cache) { // For now, just free empty slabs slab_t* slab = cache->slabs_free; int count = 0; while (slab) { slab_t* next = slab->next; if (slab_isempty(slab)) { slab_destroy(&slab); ++count; } slab = next; } cache->empty = 0; return count; }
int main(int argc, char *argv[]) { plan(4); // 1. Create slab cache srand(time(0)); const unsigned pattern = 0xdeadbeef; slab_cache_t cache; int ret = slab_cache_init(&cache, sizeof(int)); is_int(0, ret, "slab: created empty cache"); // 2. Couple alloc/free bool valid_free = true; for(int i = 0; i < 100; ++i) { int* data = (int*)slab_cache_alloc(&cache); *data = pattern; slab_free(data); if (*data == pattern) valid_free = false; } // 5. Verify freed block ok(valid_free, "slab: freed memory is correctly invalidated"); // 4. Reap memory slab_t* slab = cache.slabs_free; int free_count = 0; while (slab) { slab_t* next = slab->next; if (slab_isempty(slab)) { ++free_count; } slab = next; } int reaped = slab_cache_reap(&cache); is_int(reaped, free_count, "slab: cache reaping works"); // Stress cache int alloc_count = 73521; void** ptrs = alloca(alloc_count * sizeof(void*)); int ptrs_i = 0; for(int i = 0; i < alloc_count; ++i) { double roll = rand() / (double) RAND_MAX; if ((ptrs_i == 0) || (roll < 0.6)) { int id = ptrs_i++; ptrs[id] = slab_cache_alloc(&cache); if (ptrs[id] == 0) { ptrs_i--; } else { int* data = (int*)ptrs[id]; *data = pattern; } } else { slab_free(ptrs[--ptrs_i]); } } // 5. Delete cache slab_cache_destroy(&cache); is_int(0, cache.bufsize, "slab: freed cache"); return 0; }