Revert "semver: 1.0 -> 1"
[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 # ifdef _MSC_VER
27 typedef SECURITY_ATTRIBUTES pthread_mutexattr_t;
28
29 static inline int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a) {
30 *m = CreateMutexA(a, FALSE, NULL);
31 return !*m;
32 }
33 static inline int pthread_mutex_destroy(pthread_mutex_t *m) {
34 return !CloseHandle(*m);
35 }
36 static inline int pthread_mutex_lock(pthread_mutex_t *m) {
37 if (WaitForSingleObject(*m, INFINITE)) {
38 return 0;
39 }
40 return GetLastError();
41 }
42 static inline int pthread_mutex_unlock(pthread_mutex_t *m) {
43 return !ReleaseMutex(*m);
44 }
45 # endif
46
47 # ifndef NDEBUG
48 # include <signal.h>
49
50 const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
51 int cache_error = 0;
52
53 # endif
54
55 const size_t initial_pool_size = 64;
56
57 cache_t *cache_create(const char *name, size_t bufsize, size_t align,
58 cache_constructor_t *constructor, cache_destructor_t *destructor) {
59 cache_t *ret = calloc(1, sizeof(cache_t));
60 size_t name_length = strlen(name);
61 char *nm = calloc(1, (sizeof(char) * name_length) + 1);
62 memcpy(nm, name, name_length);
63 void **ptr = calloc(initial_pool_size, bufsize);
64 if (ret == NULL || nm == NULL || ptr == NULL || pthread_mutex_init(&ret->mutex, NULL) == -1) {
65 free(ret);
66 free(nm);
67 free(ptr);
68 return NULL;
69 }
70
71 ret->name = nm;
72 ret->ptr = ptr;
73 ret->freetotal = initial_pool_size;
74 ret->constructor = constructor;
75 ret->destructor = destructor;
76
77 # ifndef NDEBUG
78 ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
79 # else
80 ret->bufsize = bufsize;
81 # endif
82
83 (void) align;
84
85 return ret;
86 }
87
88 static inline void *get_object(void *ptr) {
89 # ifndef NDEBUG
90 uint64_t *pre = ptr;
91 return pre + 1;
92 # else
93 return ptr;
94 # endif
95 }
96
97 void cache_destroy(cache_t *cache) {
98 while (cache->freecurr > 0) {
99 void *ptr = cache->ptr[--cache->freecurr];
100 if (cache->destructor) {
101 cache->destructor(get_object(ptr), NULL);
102 }
103 free(ptr);
104 }
105 free(cache->name);
106 free(cache->ptr);
107 pthread_mutex_destroy(&cache->mutex);
108 }
109
110 void *cache_alloc(cache_t *cache) {
111 void *ret;
112 void *object;
113 pthread_mutex_lock(&cache->mutex);
114 if (cache->freecurr > 0) {
115 ret = cache->ptr[--cache->freecurr];
116 object = get_object(ret);
117 } else {
118 object = ret = malloc(cache->bufsize);
119 if (ret) {
120 object = get_object(ret);
121
122 if (cache->constructor && cache->constructor(object, NULL, 0)) {
123 free(ret);
124 object = NULL;
125 }
126 }
127 }
128 pthread_mutex_unlock(&cache->mutex);
129
130 # ifndef NDEBUG
131 if (object) {
132 /* add a simple form of buffer-check */
133 uint64_t *pre = ret;
134 *pre = redzone_pattern;
135 ret = pre + 1;
136 memcpy(((char *) ret) + cache->bufsize - (2 * sizeof(redzone_pattern)), &redzone_pattern,
137 sizeof(redzone_pattern));
138 }
139 # endif
140
141 return object;
142 }
143
144 void cache_free(cache_t *cache, void *ptr) {
145 pthread_mutex_lock(&cache->mutex);
146
147 # ifndef NDEBUG
148 /* validate redzone... */
149 if (memcmp(((char *) ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)), &redzone_pattern,
150 sizeof(redzone_pattern))
151 )
152 {
153 raise(SIGABRT);
154 cache_error = 1;
155 pthread_mutex_unlock(&cache->mutex);
156 return;
157 }
158 uint64_t *pre = ptr;
159 --pre;
160 if (*pre != redzone_pattern) {
161 raise(SIGABRT);
162 cache_error = -1;
163 pthread_mutex_unlock(&cache->mutex);
164 return;
165 }
166 ptr = pre;
167 # endif
168 if (cache->freecurr < cache->freetotal) {
169 cache->ptr[cache->freecurr++] = ptr;
170 } else {
171 /* try to enlarge free connections array */
172 size_t newtotal = cache->freetotal * 2;
173 void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
174 if (new_free) {
175 cache->freetotal = newtotal;
176 cache->ptr = new_free;
177 cache->ptr[cache->freecurr++] = ptr;
178 } else {
179 if (cache->destructor) {
180 cache->destructor(ptr, NULL);
181 }
182 free(ptr);
183 }
184 }
185 pthread_mutex_unlock(&cache->mutex);
186 }
187
188 #endif // HAVE_UMEM_H