14c86fa59STrond Norbye/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2e3ff3a18STrond Norbye#include "src/config.h"
3838846e7STrond Norbye#ifndef HAVE_UMEM_H
4838846e7STrond Norbye
54c86fa59STrond Norbye#include <stdlib.h>
64c86fa59STrond Norbye#include <string.h>
74c86fa59STrond Norbye#include <inttypes.h>
84c86fa59STrond Norbye
94c86fa59STrond Norbye#ifndef NDEBUG
104c86fa59STrond Norbye#include <signal.h>
114c86fa59STrond Norbye#endif
124c86fa59STrond Norbye
134c86fa59STrond Norbye#include "cache.h"
144c86fa59STrond Norbye
154c86fa59STrond Norbye#ifndef NDEBUG
164c86fa59STrond Norbyeconst uint64_t redzone_pattern = 0xdeadbeefcafebabe;
174c86fa59STrond Norbyeint cache_error = 0;
184c86fa59STrond Norbye#endif
194c86fa59STrond Norbye
204c86fa59STrond Norbyeconst int initial_pool_size = 64;
214c86fa59STrond Norbye
224c86fa59STrond Norbyecache_t* cache_create(const char *name, size_t bufsize, size_t align,
234c86fa59STrond Norbye                      cache_constructor_t* constructor,
244c86fa59STrond Norbye                      cache_destructor_t* destructor) {
254c86fa59STrond Norbye    cache_t* ret = calloc(1, sizeof(cache_t));
264c86fa59STrond Norbye    char* nm = strdup(name);
274c86fa59STrond Norbye    void** ptr = calloc(initial_pool_size, bufsize);
287d4ff237STrond Norbye    if (ret == NULL || nm == NULL || ptr == NULL) {
294c86fa59STrond Norbye        free(ret);
304c86fa59STrond Norbye        free(nm);
314c86fa59STrond Norbye        free(ptr);
324c86fa59STrond Norbye        return NULL;
334c86fa59STrond Norbye    }
347d4ff237STrond Norbye    cb_mutex_initialize(&ret->mutex);
354c86fa59STrond Norbye    ret->name = nm;
364c86fa59STrond Norbye    ret->ptr = ptr;
374c86fa59STrond Norbye    ret->freetotal = initial_pool_size;
384c86fa59STrond Norbye    ret->constructor = constructor;
394c86fa59STrond Norbye    ret->destructor = destructor;
404c86fa59STrond Norbye
414c86fa59STrond Norbye#ifndef NDEBUG
424c86fa59STrond Norbye    ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
434c86fa59STrond Norbye#else
444c86fa59STrond Norbye    ret->bufsize = bufsize;
454c86fa59STrond Norbye#endif
4686920c69STrond Norbye    (void)align;
474c86fa59STrond Norbye
484c86fa59STrond Norbye    return ret;
494c86fa59STrond Norbye}
504c86fa59STrond Norbye
5186920c69STrond Norbyestatic void* get_object(void *ptr) {
524c86fa59STrond Norbye#ifndef NDEBUG
534c86fa59STrond Norbye    uint64_t *pre = ptr;
544c86fa59STrond Norbye    return pre + 1;
554c86fa59STrond Norbye#endif
564c86fa59STrond Norbye    return ptr;
574c86fa59STrond Norbye}
584c86fa59STrond Norbye
594c86fa59STrond Norbyevoid cache_destroy(cache_t *cache) {
604c86fa59STrond Norbye    while (cache->freecurr > 0) {
614c86fa59STrond Norbye        void *ptr = cache->ptr[--cache->freecurr];
624c86fa59STrond Norbye        if (cache->destructor) {
634c86fa59STrond Norbye            cache->destructor(get_object(ptr), NULL);
644c86fa59STrond Norbye        }
654c86fa59STrond Norbye        free(ptr);
664c86fa59STrond Norbye    }
674c86fa59STrond Norbye    free(cache->name);
684c86fa59STrond Norbye    free(cache->ptr);
697d4ff237STrond Norbye    cb_mutex_destroy(&cache->mutex);
704c86fa59STrond Norbye}
714c86fa59STrond Norbye
724c86fa59STrond Norbyevoid* cache_alloc(cache_t *cache) {
734c86fa59STrond Norbye    void *ret;
744c86fa59STrond Norbye    void *object;
757d4ff237STrond Norbye    cb_mutex_enter(&cache->mutex);
764c86fa59STrond Norbye    if (cache->freecurr > 0) {
774c86fa59STrond Norbye        ret = cache->ptr[--cache->freecurr];
784c86fa59STrond Norbye        object = get_object(ret);
794c86fa59STrond Norbye    } else {
804c86fa59STrond Norbye        object = ret = malloc(cache->bufsize);
814c86fa59STrond Norbye        if (ret != NULL) {
824c86fa59STrond Norbye            object = get_object(ret);
834c86fa59STrond Norbye
844c86fa59STrond Norbye            if (cache->constructor != NULL &&
854c86fa59STrond Norbye                cache->constructor(object, NULL, 0) != 0) {
864c86fa59STrond Norbye                free(ret);
874c86fa59STrond Norbye                object = NULL;
884c86fa59STrond Norbye            }
894c86fa59STrond Norbye        }
904c86fa59STrond Norbye    }
917d4ff237STrond Norbye    cb_mutex_exit(&cache->mutex);
924c86fa59STrond Norbye
934c86fa59STrond Norbye#ifndef NDEBUG
944c86fa59STrond Norbye    if (object != NULL) {
954c86fa59STrond Norbye        /* add a simple form of buffer-check */
964c86fa59STrond Norbye        uint64_t *pre = ret;
974c86fa59STrond Norbye        *pre = redzone_pattern;
984c86fa59STrond Norbye        ret = pre+1;
994c86fa59STrond Norbye        memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
1004c86fa59STrond Norbye               &redzone_pattern, sizeof(redzone_pattern));
1014c86fa59STrond Norbye    }
1024c86fa59STrond Norbye#endif
1034c86fa59STrond Norbye
1044c86fa59STrond Norbye    return object;
1054c86fa59STrond Norbye}
1064c86fa59STrond Norbye
1074c86fa59STrond Norbyevoid cache_free(cache_t *cache, void *ptr) {
10886920c69STrond Norbye#ifndef NDEBUG
10986920c69STrond Norbye    uint64_t *pre;
11086920c69STrond Norbye#endif
11186920c69STrond Norbye
1127d4ff237STrond Norbye    cb_mutex_enter(&cache->mutex);
1134c86fa59STrond Norbye
1144c86fa59STrond Norbye#ifndef NDEBUG
1154c86fa59STrond Norbye    /* validate redzone... */
1164c86fa59STrond Norbye    if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
1174c86fa59STrond Norbye               &redzone_pattern, sizeof(redzone_pattern)) != 0) {
1184c86fa59STrond Norbye        raise(SIGABRT);
1194c86fa59STrond Norbye        cache_error = 1;
1207d4ff237STrond Norbye        cb_mutex_exit(&cache->mutex);
1214c86fa59STrond Norbye        return;
1224c86fa59STrond Norbye    }
12386920c69STrond Norbye    pre = ptr;
1244c86fa59STrond Norbye    --pre;
1254c86fa59STrond Norbye    if (*pre != redzone_pattern) {
1264c86fa59STrond Norbye        raise(SIGABRT);
1274c86fa59STrond Norbye        cache_error = -1;
1287d4ff237STrond Norbye        cb_mutex_exit(&cache->mutex);
1294c86fa59STrond Norbye        return;
1304c86fa59STrond Norbye    }
1314c86fa59STrond Norbye    ptr = pre;
1324c86fa59STrond Norbye#endif
1334c86fa59STrond Norbye    if (cache->freecurr < cache->freetotal) {
1344c86fa59STrond Norbye        cache->ptr[cache->freecurr++] = ptr;
1354c86fa59STrond Norbye    } else {
1364c86fa59STrond Norbye        /* try to enlarge free connections array */
1374c86fa59STrond Norbye        size_t newtotal = cache->freetotal * 2;
1384c86fa59STrond Norbye        void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
1394c86fa59STrond Norbye        if (new_free) {
140c2d0114bSTrond Norbye            cache->freetotal = (int)newtotal;
1414c86fa59STrond Norbye            cache->ptr = new_free;
1424c86fa59STrond Norbye            cache->ptr[cache->freecurr++] = ptr;
1434c86fa59STrond Norbye        } else {
1444c86fa59STrond Norbye            if (cache->destructor) {
1454c86fa59STrond Norbye                cache->destructor(ptr, NULL);
1464c86fa59STrond Norbye            }
1474c86fa59STrond Norbye            free(ptr);
1484c86fa59STrond Norbye
1494c86fa59STrond Norbye        }
1504c86fa59STrond Norbye    }
1517d4ff237STrond Norbye    cb_mutex_exit(&cache->mutex);
1524c86fa59STrond Norbye}
153838846e7STrond Norbye#endif