Disable optimizing of memset() during compilation.
[libpwmd.git] / src / mem.c
blob729aa27ca8dabd2cc534790102706a40872c274e
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <err.h>
31 #include "memzero.h"
33 #ifndef _
34 #include "gettext.h"
35 #define _(msgid) gettext(msgid)
36 #endif
38 #ifdef DEBUG
39 #ifdef HAVE_BACKTRACE
40 #include <execinfo.h>
42 #ifndef BACKTRACE
43 #define BACKTRACE(fn) { \
44 int n, nptrs; \
45 char **strings; \
46 void *buffer[20]; \
47 nptrs = backtrace(buffer, 20); \
48 strings = backtrace_symbols(buffer, nptrs); \
49 for (n = 0; n < nptrs; n++) \
50 fprintf(stderr, "BACKTRACE (%s) %i: %s\n", fn, n, strings[n]); \
51 fprintf(stderr, "\n"); \
52 fflush(stderr); \
54 #endif
55 #endif
56 #else
57 #define BACKTRACE(fn)
58 #endif
60 #include "mem.h"
62 #ifdef USE_PTH_THREADS
63 #include <pth.h>
64 #else
65 #include <pthread.h>
66 #endif
68 #ifndef _
69 #define _ gettext(msgid)
70 #endif
72 struct memlist_s {
73 void *ptr;
74 size_t size;
75 struct memlist_s *next;
78 static struct memlist_s *memlist;
79 #ifdef USE_PTH_THREADS
80 static pth_mutex_t mem_mutex;
81 #else
82 static pthread_mutex_t mem_mutex;
83 #endif
84 #ifdef DEBUG
85 static size_t allocations, deallocations;
86 #endif
88 void _xmem_init()
90 static int init;
92 if (!init)
93 #ifdef USE_PTH_THREADS
94 pth_mutex_init(&mem_mutex);
95 #else
96 pthread_mutex_init(&mem_mutex, NULL);
97 #endif
99 init = 1;
102 static int memlist_remove(void *ptr, const char *func)
104 struct memlist_s *m, *last = NULL, *p;
106 #ifdef USE_PTH_THREADS
107 pth_mutex_acquire(&mem_mutex, 0, NULL);
108 #else
109 pthread_mutex_lock(&mem_mutex);
110 #endif
112 for (m = memlist; m; m = m->next) {
113 if (m->ptr == ptr) {
114 #ifdef DEBUG
115 fprintf(stderr, "%s: %p %i\n", func, ptr, m->size);
116 #endif
117 memzero(m->ptr, m->size);
118 free(m->ptr);
120 p = m->next;
121 free(m);
122 #ifdef DEBUG
123 deallocations++;
124 #endif
126 if (last)
127 last->next = p;
128 else
129 memlist = p;
131 #ifdef USE_PTH_THREADS
132 pth_mutex_release(&mem_mutex);
133 #else
134 pthread_mutex_unlock(&mem_mutex);
135 #endif
136 return 1;
139 last = m;
142 #ifdef USE_PTH_THREADS
143 pth_mutex_release(&mem_mutex);
144 #else
145 pthread_mutex_unlock(&mem_mutex);
146 #endif
147 return 0;
150 static void memlist_prepend(struct memlist_s *new)
152 #ifdef USE_PTH_THREADS
153 pth_mutex_acquire(&mem_mutex, 0, NULL);
154 #else
155 pthread_mutex_lock(&mem_mutex);
156 #endif
157 #ifdef DEBUG
158 allocations++;
159 #endif
160 new->next = memlist;
161 memlist = new;
162 #ifdef USE_PTH_THREADS
163 pth_mutex_release(&mem_mutex);
164 #else
165 pthread_mutex_unlock(&mem_mutex);
166 #endif
169 void _xfree(void *ptr)
171 if (!ptr)
172 return;
174 if (!memlist_remove(ptr, __FUNCTION__)) {
175 warnx(_("%s: %p not found"), __FUNCTION__, ptr);
176 assert(0);
180 void *_xmalloc(size_t size)
182 void *p;
183 struct memlist_s *m;
185 if ((m = (struct memlist_s *)malloc(sizeof(struct memlist_s))) == NULL)
186 return NULL;
188 if ((p = (void *)malloc(size)) == NULL) {
189 free(m);
190 return NULL;
193 m->ptr = p;
194 m->size = size;
195 memlist_prepend(m);
196 #ifdef DEBUG
197 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, p, size);
198 BACKTRACE(__FUNCTION__);
199 #endif
200 return m->ptr;
203 void *_xcalloc(size_t nmemb, size_t size)
205 void *p;
206 struct memlist_s *m;
208 if ((m = (struct memlist_s *)malloc(sizeof(struct memlist_s))) == NULL)
209 return NULL;
211 if ((p = calloc(nmemb, size)) == NULL) {
212 free(m);
213 return NULL;
216 m->ptr = p;
217 m->size = nmemb * size;
218 memlist_prepend(m);
219 #ifdef DEBUG
220 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, p, nmemb * size);
221 BACKTRACE(__FUNCTION__);
222 #endif
223 return m->ptr;
226 void *_xrealloc(void *ptr, size_t size)
228 void *p;
229 struct memlist_s *m;
231 if (!size && ptr) {
232 _xfree(ptr);
233 return NULL;
236 if (!ptr)
237 return _xmalloc(size);
239 #ifdef USE_PTH_THREADS
240 pth_mutex_acquire(&mem_mutex, 0, NULL);
241 #else
242 pthread_mutex_lock(&mem_mutex);
243 #endif
245 for (m = memlist; m; m = m->next) {
246 if (m->ptr == ptr) {
247 if ((p = (void *)malloc(size)) == NULL) {
248 #ifdef USE_PTH_THREADS
249 pth_mutex_release(&mem_mutex);
250 #else
251 pthread_mutex_unlock(&mem_mutex);
252 #endif
253 return NULL;
256 memcpy(p, m->ptr, size < m->size ? size : m->size);
257 memzero(m->ptr, m->size);
258 free(m->ptr);
259 m->ptr = p;
260 m->size = size;
261 #ifdef DEBUG
262 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, p, size);
263 BACKTRACE(__FUNCTION__);
264 #endif
265 #ifdef USE_PTH_THREADS
266 pth_mutex_release(&mem_mutex);
267 #else
268 pthread_mutex_unlock(&mem_mutex);
269 #endif
270 return m->ptr;
274 warnx(_("%s: %p not found"), __FUNCTION__, ptr);
275 #ifdef USE_PTH_THREADS
276 pth_mutex_release(&mem_mutex);
277 #else
278 pthread_mutex_unlock(&mem_mutex);
279 #endif
280 assert(0);
281 return NULL;
284 void _xpanic(void)
286 struct memlist_s *m;
288 #ifdef USE_PTH_THREADS
289 pth_mutex_acquire(&mem_mutex, 0, NULL);
290 #else
291 pthread_mutex_lock(&mem_mutex);
292 #endif
294 for (m = memlist; m; m = memlist)
295 _xfree(m->ptr);
297 #ifdef USE_PTH_THREADS
298 pth_mutex_release(&mem_mutex);
299 #else
300 pthread_mutex_unlock(&mem_mutex);
301 #endif
304 #ifdef DEBUG
305 void xdump(void)
307 struct memlist_s *m;
308 size_t total = 0;
310 #ifdef USE_PTH_THREADS
311 pth_mutex_acquire(&mem_mutex, 0, NULL);
312 #else
313 pthread_mutex_lock(&mem_mutex);
314 #endif
316 for (m = memlist; m; m = m->next) {
317 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, m->ptr, m->size);
318 total += m->size;
321 fprintf(stderr, "Total unfreed: %i bytes, allocations: %i, deallocations: %i\n", total,
322 allocations, deallocations);
323 #ifdef USE_PTH_THREADS
324 pth_mutex_release(&mem_mutex);
325 #else
326 pthread_mutex_unlock(&mem_mutex);
327 #endif
329 #endif