From 908ec15cb33e27cc49dd0659a087b230ddb9435b Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Fri, 26 Oct 2007 15:12:12 +0000 Subject: [PATCH] slab allocator improvements - keep track of slabs - allow deallocation of whole cache - default alignment from sys/param.h - allow NULL helper functions - keep copy of name --- src/slab.c | 158 ++++++++++++++++++++++++++++++++++++++--------------- src/slab.h | 4 +- 2 files changed, 117 insertions(+), 45 deletions(-) diff --git a/src/slab.c b/src/slab.c index 30a485a..d91ffac 100644 --- a/src/slab.c +++ b/src/slab.c @@ -17,101 +17,171 @@ */ /* - * SLAB-like allocator, but without the complexities of deallocation... + * Primitive slab allocator. * * - On first alloc initializer is called for all objects. * - On each release, cleaner is called. * - When giving object out, nothing is done. - * - Writes obj header with List struct, expects it to be overwritten on use. + * - Writes List struct on obj header, expects it to be overwritten on use. */ -#include "system.h" -#include "list.h" -#include "slab.h" +#include + +#include "bouncer.h" + +#define CUSTOM_ALIGN(x, a) (((unsigned long)(x) + (a)) & ~(a)) + +#ifndef ALIGN +#define ALIGN(x) CUSTOM_ALIGN(x, sizeof(long)) +#endif /* - * Stores pre-initialized objects of one type. + * Store for pre-initialized objects of one type. */ struct ObjectCache { List head; StatList freelist; - const char *name; - int obj_size; - int align; - int total_count; + StatList slablist; + char name[32]; + unsigned final_size; + unsigned total_count; obj_init_fn init_func; obj_clean_fn clean_func; }; +/* + * Header for each slab. + */ +struct Slab { + List head; +}; + /* keep track of all caches */ static STATLIST(objcache_list); -/* make new cache */ -ObjectCache * objcache_create(const char *name, int obj_size, int align, - obj_init_fn init_func, - obj_clean_fn clean_func) +/* cache for cache headers */ +static ObjectCache *objcache_cache = NULL; + +/* fill struct contents */ +static void init_objcache(ObjectCache *cache, + const char *name, + unsigned obj_size, + unsigned align, + obj_init_fn init_func, + obj_clean_fn clean_func) { - ObjectCache *cache = malloc(sizeof(*cache)); - if (!cache) - return NULL; list_init(&cache->head); statlist_init(&cache->freelist, name); - cache->name = name; - cache->obj_size = obj_size; - cache->align = align; + statlist_init(&cache->slablist, name); + strlcpy(cache->name, name, sizeof(cache->name)); cache->total_count = 0; cache->init_func = init_func; cache->clean_func = clean_func; statlist_append(&cache->head, &objcache_list); + if (align == 0) + cache->final_size = ALIGN(obj_size); + else + cache->final_size = CUSTOM_ALIGN(obj_size, align); +} + +/* make new cache */ +ObjectCache * objcache_create(const char *name, + unsigned obj_size, + unsigned align, + obj_init_fn init_func, + obj_clean_fn clean_func) +{ + ObjectCache *cache; + + /* main cache */ + if (!objcache_cache) { + objcache_cache = malloc(sizeof(ObjectCache)); + if (!objcache_cache) + return NULL; + init_objcache(objcache_cache, "objcache_cache", + sizeof(ObjectCache), 0, NULL, NULL); + } + + /* new cache object */ + cache = obj_alloc(objcache_cache); + if (cache) + init_objcache(cache, name, obj_size, align, + init_func, clean_func); return cache; } +/* free all storage associated by cache */ +void objcache_destroy(ObjectCache *cache) +{ + List *item, *tmp; + struct Slab *slab; + + statlist_for_each_safe(item, &cache->slablist, tmp) { + slab = container_of(item, struct Slab, head); + free(slab); + } + statlist_remove(&cache->head, &objcache_list); + memset(cache, 0, sizeof(*cache)); + obj_free(objcache_cache, cache); +} + /* add new block of objects to cache */ static void grow(ObjectCache *cache) { - int count, i, real_size; + unsigned count, i, size; char *area; - - real_size = (cache->obj_size + cache->align - 1) & ~(cache->align - 1); - - count = 8192 / real_size; - if (count < 20) - count = 20; - - area = malloc(count * real_size); - if (!area) + struct Slab *slab; + + /* calc new slab size */ + count = cache->total_count; + if (count < 50) + count = 16 * 1024 / cache->final_size; + if (count < 50) + count = 50; + size = count * cache->final_size; + + /* allocate & init */ + slab = malloc(size + sizeof(struct Slab)); + if (!slab) return; + list_init(&slab->head); + area = (char *)slab + sizeof(struct Slab); + memset(area, 0, size); - memset(area, 0, count * real_size); + /* init objects */ for (i = 0; i < count; i++) { - void *obj = area + i * real_size; - cache->init_func(obj); - statlist_append((List *)obj, &cache->freelist); + void *obj = area + i * cache->final_size; + List *head = (List *)obj; + + if (cache->init_func) + cache->init_func(obj); + list_init(head); + statlist_append(head, &cache->freelist); } + /* register to cache */ cache->total_count += count; + statlist_append(&slab->head, &cache->slablist); } /* get free object from cache */ void *obj_alloc(ObjectCache *cache) { - List *item; - - item = statlist_pop(&cache->freelist); - if (item) - return item; - - grow(cache); - - return statlist_pop(&cache->freelist); + List *item = statlist_pop(&cache->freelist); + if (!item) { + grow(cache); + item = statlist_pop(&cache->freelist); + } + return item; } /* put object back to cache */ void obj_free(ObjectCache *cache, void *obj) { List *item = obj; - cache->clean_func(obj); + if (cache->clean_func) + cache->clean_func(obj); statlist_prepend(item, &cache->freelist); } diff --git a/src/slab.h b/src/slab.h index eebcbe9..ae591c1 100644 --- a/src/slab.h +++ b/src/slab.h @@ -4,8 +4,9 @@ typedef struct ObjectCache ObjectCache; typedef void (*obj_init_fn)(void *obj); typedef void (*obj_clean_fn)(void *obj); -ObjectCache *objcache_create(const char *name, int obj_size, int align, +ObjectCache *objcache_create(const char *name, unsigned obj_size, unsigned align, obj_init_fn init_func, obj_clean_fn clean_func); +void objcache_destroy(ObjectCache *cache); void * obj_alloc(ObjectCache *cache); void obj_free(ObjectCache *cache, void *obj); @@ -14,3 +15,4 @@ int objcache_total_count(ObjectCache *cache); int objcache_free_count(ObjectCache *cache); int objcache_active_count(ObjectCache *cache); + -- 2.40.0