xref: /memcached-1.4.29/cache.c (revision 1d0978c5)
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 
cache_create(const char * name,size_t bufsize,size_t align,cache_constructor_t * constructor,cache_destructor_t * destructor)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, sizeof(void*));
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 
get_object(void * ptr)48 static inline void* get_object(void *ptr) {
49 #ifndef NDEBUG
50     uint64_t *pre = ptr;
51     return pre + 1;
52 #else
53     return ptr;
54 #endif
55 }
56 
cache_destroy(cache_t * cache)57 void cache_destroy(cache_t *cache) {
58     while (cache->freecurr > 0) {
59         void *ptr = cache->ptr[--cache->freecurr];
60         if (cache->destructor) {
61             cache->destructor(get_object(ptr), NULL);
62         }
63         free(ptr);
64     }
65     free(cache->name);
66     free(cache->ptr);
67     pthread_mutex_destroy(&cache->mutex);
68     free(cache);
69 }
70 
cache_alloc(cache_t * cache)71 void* cache_alloc(cache_t *cache) {
72     void *ret;
73     void *object;
74     pthread_mutex_lock(&cache->mutex);
75     if (cache->freecurr > 0) {
76         ret = cache->ptr[--cache->freecurr];
77         object = get_object(ret);
78     } else {
79         object = ret = malloc(cache->bufsize);
80         if (ret != NULL) {
81             object = get_object(ret);
82 
83             if (cache->constructor != NULL &&
84                 cache->constructor(object, NULL, 0) != 0) {
85                 free(ret);
86                 object = NULL;
87             }
88         }
89     }
90     pthread_mutex_unlock(&cache->mutex);
91 
92 #ifndef NDEBUG
93     if (object != NULL) {
94         /* add a simple form of buffer-check */
95         uint64_t *pre = ret;
96         *pre = redzone_pattern;
97         ret = pre+1;
98         memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
99                &redzone_pattern, sizeof(redzone_pattern));
100     }
101 #endif
102 
103     return object;
104 }
105 
cache_free(cache_t * cache,void * ptr)106 void cache_free(cache_t *cache, void *ptr) {
107     pthread_mutex_lock(&cache->mutex);
108 
109 #ifndef NDEBUG
110     /* validate redzone... */
111     if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
112                &redzone_pattern, sizeof(redzone_pattern)) != 0) {
113         raise(SIGABRT);
114         cache_error = 1;
115         pthread_mutex_unlock(&cache->mutex);
116         return;
117     }
118     uint64_t *pre = ptr;
119     --pre;
120     if (*pre != redzone_pattern) {
121         raise(SIGABRT);
122         cache_error = -1;
123         pthread_mutex_unlock(&cache->mutex);
124         return;
125     }
126     ptr = pre;
127 #endif
128     if (cache->freecurr < cache->freetotal) {
129         cache->ptr[cache->freecurr++] = ptr;
130     } else {
131         /* try to enlarge free connections array */
132         size_t newtotal = cache->freetotal * 2;
133         void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
134         if (new_free) {
135             cache->freetotal = newtotal;
136             cache->ptr = new_free;
137             cache->ptr[cache->freecurr++] = ptr;
138         } else {
139             if (cache->destructor) {
140                 cache->destructor(ptr, NULL);
141             }
142             free(ptr);
143 
144         }
145     }
146     pthread_mutex_unlock(&cache->mutex);
147 }
148 
149