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