14c86fa59STrond Norbye /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
24c86fa59STrond Norbye #include <stdlib.h>
34c86fa59STrond Norbye #include <string.h>
44c86fa59STrond Norbye #include <inttypes.h>
54c86fa59STrond Norbye
64c86fa59STrond Norbye #ifndef NDEBUG
74c86fa59STrond Norbye #include <signal.h>
84c86fa59STrond Norbye #endif
94c86fa59STrond Norbye
104c86fa59STrond Norbye #include "cache.h"
114c86fa59STrond Norbye
124c86fa59STrond Norbye #ifndef NDEBUG
134c86fa59STrond Norbye const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
144c86fa59STrond Norbye int cache_error = 0;
154c86fa59STrond Norbye #endif
164c86fa59STrond Norbye
174c86fa59STrond Norbye const int initial_pool_size = 64;
184c86fa59STrond Norbye
cache_create(const char * name,size_t bufsize,size_t align,cache_constructor_t * constructor,cache_destructor_t * destructor)194c86fa59STrond Norbye cache_t* cache_create(const char *name, size_t bufsize, size_t align,
204c86fa59STrond Norbye cache_constructor_t* constructor,
214c86fa59STrond Norbye cache_destructor_t* destructor) {
224c86fa59STrond Norbye cache_t* ret = calloc(1, sizeof(cache_t));
234c86fa59STrond Norbye char* nm = strdup(name);
2416a809e2STrond Norbye void** ptr = calloc(initial_pool_size, sizeof(void*));
254c86fa59STrond Norbye if (ret == NULL || nm == NULL || ptr == NULL ||
264c86fa59STrond Norbye pthread_mutex_init(&ret->mutex, NULL) == -1) {
274c86fa59STrond Norbye free(ret);
284c86fa59STrond Norbye free(nm);
294c86fa59STrond Norbye free(ptr);
304c86fa59STrond Norbye return NULL;
314c86fa59STrond Norbye }
324c86fa59STrond Norbye
334c86fa59STrond Norbye ret->name = nm;
344c86fa59STrond Norbye ret->ptr = ptr;
354c86fa59STrond Norbye ret->freetotal = initial_pool_size;
364c86fa59STrond Norbye ret->constructor = constructor;
374c86fa59STrond Norbye ret->destructor = destructor;
384c86fa59STrond Norbye
394c86fa59STrond Norbye #ifndef NDEBUG
404c86fa59STrond Norbye ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
414c86fa59STrond Norbye #else
424c86fa59STrond Norbye ret->bufsize = bufsize;
434c86fa59STrond Norbye #endif
444c86fa59STrond Norbye
454c86fa59STrond Norbye return ret;
464c86fa59STrond Norbye }
474c86fa59STrond Norbye
get_object(void * ptr)484c86fa59STrond Norbye static inline void* get_object(void *ptr) {
494c86fa59STrond Norbye #ifndef NDEBUG
504c86fa59STrond Norbye uint64_t *pre = ptr;
514c86fa59STrond Norbye return pre + 1;
528c0a1083STrond Norbye #else
534c86fa59STrond Norbye return ptr;
548c0a1083STrond Norbye #endif
554c86fa59STrond Norbye }
564c86fa59STrond Norbye
cache_destroy(cache_t * cache)574c86fa59STrond Norbye void cache_destroy(cache_t *cache) {
584c86fa59STrond Norbye while (cache->freecurr > 0) {
594c86fa59STrond Norbye void *ptr = cache->ptr[--cache->freecurr];
604c86fa59STrond Norbye if (cache->destructor) {
614c86fa59STrond Norbye cache->destructor(get_object(ptr), NULL);
624c86fa59STrond Norbye }
634c86fa59STrond Norbye free(ptr);
644c86fa59STrond Norbye }
654c86fa59STrond Norbye free(cache->name);
664c86fa59STrond Norbye free(cache->ptr);
674c86fa59STrond Norbye pthread_mutex_destroy(&cache->mutex);
68*1d0978c5Sdormando free(cache);
694c86fa59STrond Norbye }
704c86fa59STrond Norbye
cache_alloc(cache_t * cache)714c86fa59STrond Norbye void* cache_alloc(cache_t *cache) {
724c86fa59STrond Norbye void *ret;
734c86fa59STrond Norbye void *object;
744c86fa59STrond Norbye pthread_mutex_lock(&cache->mutex);
754c86fa59STrond Norbye if (cache->freecurr > 0) {
764c86fa59STrond Norbye ret = cache->ptr[--cache->freecurr];
774c86fa59STrond Norbye object = get_object(ret);
784c86fa59STrond Norbye } else {
794c86fa59STrond Norbye object = ret = malloc(cache->bufsize);
804c86fa59STrond Norbye if (ret != NULL) {
814c86fa59STrond Norbye object = get_object(ret);
824c86fa59STrond Norbye
834c86fa59STrond Norbye if (cache->constructor != NULL &&
844c86fa59STrond Norbye cache->constructor(object, NULL, 0) != 0) {
854c86fa59STrond Norbye free(ret);
864c86fa59STrond Norbye object = NULL;
874c86fa59STrond Norbye }
884c86fa59STrond Norbye }
894c86fa59STrond Norbye }
904c86fa59STrond Norbye pthread_mutex_unlock(&cache->mutex);
914c86fa59STrond Norbye
924c86fa59STrond Norbye #ifndef NDEBUG
934c86fa59STrond Norbye if (object != NULL) {
944c86fa59STrond Norbye /* add a simple form of buffer-check */
954c86fa59STrond Norbye uint64_t *pre = ret;
964c86fa59STrond Norbye *pre = redzone_pattern;
974c86fa59STrond Norbye ret = pre+1;
984c86fa59STrond Norbye memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
994c86fa59STrond Norbye &redzone_pattern, sizeof(redzone_pattern));
1004c86fa59STrond Norbye }
1014c86fa59STrond Norbye #endif
1024c86fa59STrond Norbye
1034c86fa59STrond Norbye return object;
1044c86fa59STrond Norbye }
1054c86fa59STrond Norbye
cache_free(cache_t * cache,void * ptr)1064c86fa59STrond Norbye void cache_free(cache_t *cache, void *ptr) {
1074c86fa59STrond Norbye pthread_mutex_lock(&cache->mutex);
1084c86fa59STrond Norbye
1094c86fa59STrond Norbye #ifndef NDEBUG
1104c86fa59STrond Norbye /* validate redzone... */
1114c86fa59STrond Norbye if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
1124c86fa59STrond Norbye &redzone_pattern, sizeof(redzone_pattern)) != 0) {
1134c86fa59STrond Norbye raise(SIGABRT);
1144c86fa59STrond Norbye cache_error = 1;
1154c86fa59STrond Norbye pthread_mutex_unlock(&cache->mutex);
1164c86fa59STrond Norbye return;
1174c86fa59STrond Norbye }
1184c86fa59STrond Norbye uint64_t *pre = ptr;
1194c86fa59STrond Norbye --pre;
1204c86fa59STrond Norbye if (*pre != redzone_pattern) {
1214c86fa59STrond Norbye raise(SIGABRT);
1224c86fa59STrond Norbye cache_error = -1;
1234c86fa59STrond Norbye pthread_mutex_unlock(&cache->mutex);
1244c86fa59STrond Norbye return;
1254c86fa59STrond Norbye }
1264c86fa59STrond Norbye ptr = pre;
1274c86fa59STrond Norbye #endif
1284c86fa59STrond Norbye if (cache->freecurr < cache->freetotal) {
1294c86fa59STrond Norbye cache->ptr[cache->freecurr++] = ptr;
1304c86fa59STrond Norbye } else {
1314c86fa59STrond Norbye /* try to enlarge free connections array */
1324c86fa59STrond Norbye size_t newtotal = cache->freetotal * 2;
1334c86fa59STrond Norbye void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
1344c86fa59STrond Norbye if (new_free) {
1354c86fa59STrond Norbye cache->freetotal = newtotal;
1364c86fa59STrond Norbye cache->ptr = new_free;
1374c86fa59STrond Norbye cache->ptr[cache->freecurr++] = ptr;
1384c86fa59STrond Norbye } else {
1394c86fa59STrond Norbye if (cache->destructor) {
1404c86fa59STrond Norbye cache->destructor(ptr, NULL);
1414c86fa59STrond Norbye }
1424c86fa59STrond Norbye free(ptr);
1434c86fa59STrond Norbye
1444c86fa59STrond Norbye }
1454c86fa59STrond Norbye }
1464c86fa59STrond Norbye pthread_mutex_unlock(&cache->mutex);
1474c86fa59STrond Norbye }
1484c86fa59STrond Norbye
149