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