more cleanup
[m6w6/libmemcached] / src / libmemcachedprotocol / cache.c
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "mem_config.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <inttypes.h>
21
22 #include "libmemcachedprotocol/common.h"
23
24 #ifndef HAVE_UMEM_H
25
26 # ifndef NDEBUG
27 # include <signal.h>
28
29 const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
30 int cache_error = 0;
31
32 # endif
33
34 const size_t initial_pool_size = 64;
35
36 cache_t *cache_create(const char *name, size_t bufsize, size_t align,
37 cache_constructor_t *constructor, cache_destructor_t *destructor) {
38 cache_t *ret = calloc(1, sizeof(cache_t));
39 size_t name_length = strlen(name);
40 char *nm = calloc(1, (sizeof(char) * name_length) + 1);
41 memcpy(nm, name, name_length);
42 void **ptr = calloc(initial_pool_size, bufsize);
43 if (ret == NULL || nm == NULL || ptr == NULL || 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 (void) align;
63
64 return ret;
65 }
66
67 static inline void *get_object(void *ptr) {
68 # ifndef NDEBUG
69 uint64_t *pre = ptr;
70 return pre + 1;
71 # else
72 return ptr;
73 # endif
74 }
75
76 void cache_destroy(cache_t *cache) {
77 while (cache->freecurr > 0) {
78 void *ptr = cache->ptr[--cache->freecurr];
79 if (cache->destructor) {
80 cache->destructor(get_object(ptr), NULL);
81 }
82 free(ptr);
83 }
84 free(cache->name);
85 free(cache->ptr);
86 pthread_mutex_destroy(&cache->mutex);
87 }
88
89 void *cache_alloc(cache_t *cache) {
90 void *ret;
91 void *object;
92 pthread_mutex_lock(&cache->mutex);
93 if (cache->freecurr > 0) {
94 ret = cache->ptr[--cache->freecurr];
95 object = get_object(ret);
96 } else {
97 object = ret = malloc(cache->bufsize);
98 if (ret) {
99 object = get_object(ret);
100
101 if (cache->constructor && cache->constructor(object, NULL, 0)) {
102 free(ret);
103 object = NULL;
104 }
105 }
106 }
107 pthread_mutex_unlock(&cache->mutex);
108
109 # ifndef NDEBUG
110 if (object) {
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)), &redzone_pattern,
116 sizeof(redzone_pattern));
117 }
118 # endif
119
120 return object;
121 }
122
123 void cache_free(cache_t *cache, void *ptr) {
124 pthread_mutex_lock(&cache->mutex);
125
126 # ifndef NDEBUG
127 /* validate redzone... */
128 if (memcmp(((char *) ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)), &redzone_pattern,
129 sizeof(redzone_pattern))
130 )
131 {
132 raise(SIGABRT);
133 cache_error = 1;
134 pthread_mutex_unlock(&cache->mutex);
135 return;
136 }
137 uint64_t *pre = ptr;
138 --pre;
139 if (*pre != redzone_pattern) {
140 raise(SIGABRT);
141 cache_error = -1;
142 pthread_mutex_unlock(&cache->mutex);
143 return;
144 }
145 ptr = pre;
146 # endif
147 if (cache->freecurr < cache->freetotal) {
148 cache->ptr[cache->freecurr++] = ptr;
149 } else {
150 /* try to enlarge free connections array */
151 size_t newtotal = cache->freetotal * 2;
152 void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
153 if (new_free) {
154 cache->freetotal = newtotal;
155 cache->ptr = new_free;
156 cache->ptr[cache->freecurr++] = ptr;
157 } else {
158 if (cache->destructor) {
159 cache->destructor(ptr, NULL);
160 }
161 free(ptr);
162 }
163 }
164 pthread_mutex_unlock(&cache->mutex);
165 }
166
167 #endif // HAVE_UMEM_H