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