1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 #include <stdlib.h> 3 #include <string.h> 4 #include <inttypes.h> 5 6 #ifndef NDEBUG 7 #include <signal.h> 8 #endif 9 10 #include "cache.h" 11 12 #ifndef NDEBUG 13 const uint64_t redzone_pattern = 0xdeadbeefcafebabe; 14 int cache_error = 0; 15 #endif 16 17 const int initial_pool_size = 64; 18 19 cache_t* cache_create(const char *name, size_t bufsize, size_t align, 20 cache_constructor_t* constructor, 21 cache_destructor_t* destructor) { 22 cache_t* ret = calloc(1, sizeof(cache_t)); 23 char* nm = strdup(name); 24 void** ptr = calloc(initial_pool_size, bufsize); 25 if (ret == NULL || nm == NULL || ptr == NULL || 26 pthread_mutex_init(&ret->mutex, NULL) == -1) { 27 free(ret); 28 free(nm); 29 free(ptr); 30 return NULL; 31 } 32 33 ret->name = nm; 34 ret->ptr = ptr; 35 ret->freetotal = initial_pool_size; 36 ret->constructor = constructor; 37 ret->destructor = destructor; 38 39 #ifndef NDEBUG 40 ret->bufsize = bufsize + 2 * sizeof(redzone_pattern); 41 #else 42 ret->bufsize = bufsize; 43 #endif 44 45 return ret; 46 } 47 48 static inline void* get_object(void *ptr) { 49 #ifndef NDEBUG 50 uint64_t *pre = ptr; 51 return pre + 1; 52 #endif 53 return ptr; 54 } 55 56 void cache_destroy(cache_t *cache) { 57 while (cache->freecurr > 0) { 58 void *ptr = cache->ptr[--cache->freecurr]; 59 if (cache->destructor) { 60 cache->destructor(get_object(ptr), NULL); 61 } 62 free(ptr); 63 } 64 free(cache->name); 65 free(cache->ptr); 66 pthread_mutex_destroy(&cache->mutex); 67 } 68 69 void* cache_alloc(cache_t *cache) { 70 void *ret; 71 void *object; 72 pthread_mutex_lock(&cache->mutex); 73 if (cache->freecurr > 0) { 74 ret = cache->ptr[--cache->freecurr]; 75 object = get_object(ret); 76 } else { 77 object = ret = malloc(cache->bufsize); 78 if (ret != NULL) { 79 object = get_object(ret); 80 81 if (cache->constructor != NULL && 82 cache->constructor(object, NULL, 0) != 0) { 83 free(ret); 84 object = NULL; 85 } 86 } 87 } 88 pthread_mutex_unlock(&cache->mutex); 89 90 #ifndef NDEBUG 91 if (object != NULL) { 92 /* add a simple form of buffer-check */ 93 uint64_t *pre = ret; 94 *pre = redzone_pattern; 95 ret = pre+1; 96 memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)), 97 &redzone_pattern, sizeof(redzone_pattern)); 98 } 99 #endif 100 101 return object; 102 } 103 104 void cache_free(cache_t *cache, void *ptr) { 105 pthread_mutex_lock(&cache->mutex); 106 107 #ifndef NDEBUG 108 /* validate redzone... */ 109 if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)), 110 &redzone_pattern, sizeof(redzone_pattern)) != 0) { 111 raise(SIGABRT); 112 cache_error = 1; 113 pthread_mutex_unlock(&cache->mutex); 114 return; 115 } 116 uint64_t *pre = ptr; 117 --pre; 118 if (*pre != redzone_pattern) { 119 raise(SIGABRT); 120 cache_error = -1; 121 pthread_mutex_unlock(&cache->mutex); 122 return; 123 } 124 ptr = pre; 125 #endif 126 if (cache->freecurr < cache->freetotal) { 127 cache->ptr[cache->freecurr++] = ptr; 128 } else { 129 /* try to enlarge free connections array */ 130 size_t newtotal = cache->freetotal * 2; 131 void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal); 132 if (new_free) { 133 cache->freetotal = newtotal; 134 cache->ptr = new_free; 135 cache->ptr[cache->freecurr++] = ptr; 136 } else { 137 if (cache->destructor) { 138 cache->destructor(ptr, NULL); 139 } 140 free(ptr); 141 142 } 143 } 144 pthread_mutex_unlock(&cache->mutex); 145 } 146 147