Version 3.0.0.
[pwmd.git] / src / mem.c
blobbfd271939f19ff00e28615e18f17b6206452468f
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd 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 Pwmd 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 Pwmd. 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
74 void *ptr;
75 size_t size;
76 struct memlist_s *next;
79 static struct memlist_s *memlist;
80 #ifdef USE_PTH_THREADS
81 static pth_mutex_t mem_mutex;
82 #else
83 static pthread_mutex_t mem_mutex;
84 #endif
85 #ifdef DEBUG
86 static size_t allocations, deallocations;
87 #endif
89 void
90 xmem_init ()
92 static int init;
94 if (!init)
95 #ifdef USE_PTH_THREADS
96 pth_mutex_init (&mem_mutex);
97 #else
98 pthread_mutex_init (&mem_mutex, NULL);
99 #endif
101 init = 1;
104 static int
105 memlist_remove (void *ptr, const char *func)
107 struct memlist_s *m, *last = NULL, *p;
109 #ifdef USE_PTH_THREADS
110 pth_mutex_acquire (&mem_mutex, 0, NULL);
111 #else
112 pthread_mutex_lock (&mem_mutex);
113 #endif
115 for (m = memlist; m; m = m->next)
117 if (m->ptr == ptr)
119 #ifdef DEBUG
120 fprintf (stderr, "%s: %p %i\n", func, ptr, m->size);
121 #endif
122 memzero (m->ptr, m->size);
123 free (m->ptr);
125 p = m->next;
126 free (m);
127 #ifdef DEBUG
128 deallocations++;
129 #endif
131 if (last)
132 last->next = p;
133 else
134 memlist = p;
136 #ifdef USE_PTH_THREADS
137 pth_mutex_release (&mem_mutex);
138 #else
139 pthread_mutex_unlock (&mem_mutex);
140 #endif
141 return 1;
144 last = m;
147 #ifdef USE_PTH_THREADS
148 pth_mutex_release (&mem_mutex);
149 #else
150 pthread_mutex_unlock (&mem_mutex);
151 #endif
152 return 0;
155 static void
156 memlist_prepend (struct memlist_s *new)
158 #ifdef USE_PTH_THREADS
159 pth_mutex_acquire (&mem_mutex, 0, NULL);
160 #else
161 pthread_mutex_lock (&mem_mutex);
162 #endif
163 #ifdef DEBUG
164 allocations++;
165 #endif
166 new->next = memlist;
167 memlist = new;
168 #ifdef USE_PTH_THREADS
169 pth_mutex_release (&mem_mutex);
170 #else
171 pthread_mutex_unlock (&mem_mutex);
172 #endif
175 void
176 xfree (void *ptr)
178 if (!ptr)
179 return;
181 if (!memlist_remove (ptr, __FUNCTION__))
183 warnx (_("%s: %p not found"), __FUNCTION__, ptr);
184 assert (0);
188 void *
189 xmalloc (size_t size)
191 void *p;
192 struct memlist_s *m;
194 if ((m = (struct memlist_s *) malloc (sizeof (struct memlist_s))) == NULL)
195 return NULL;
197 if ((p = (void *) malloc (size)) == NULL)
199 free (m);
200 return NULL;
203 m->ptr = p;
204 m->size = size;
205 memlist_prepend (m);
206 #ifdef DEBUG
207 fprintf (stderr, "%s: %p %i\n", __FUNCTION__, p, size);
208 BACKTRACE (__FUNCTION__);
209 #endif
210 return m->ptr;
213 void *
214 xcalloc (size_t nmemb, size_t size)
216 void *p;
217 struct memlist_s *m;
219 if ((m = (struct memlist_s *) malloc (sizeof (struct memlist_s))) == NULL)
220 return NULL;
222 if ((p = calloc (nmemb, size)) == NULL)
224 free (m);
225 return NULL;
228 m->ptr = p;
229 m->size = nmemb * size;
230 memlist_prepend (m);
231 #ifdef DEBUG
232 fprintf (stderr, "%s: %p %i\n", __FUNCTION__, p, nmemb * size);
233 BACKTRACE (__FUNCTION__);
234 #endif
235 return m->ptr;
238 void *
239 xrealloc (void *ptr, size_t size)
241 void *p;
242 struct memlist_s *m;
244 if (!size && ptr)
246 xfree (ptr);
247 return NULL;
250 if (!ptr)
251 return xmalloc (size);
253 #ifdef USE_PTH_THREADS
254 pth_mutex_acquire (&mem_mutex, 0, NULL);
255 #else
256 pthread_mutex_lock (&mem_mutex);
257 #endif
259 for (m = memlist; m; m = m->next)
261 if (m->ptr == ptr)
263 if ((p = (void *) malloc (size)) == NULL)
265 #ifdef USE_PTH_THREADS
266 pth_mutex_release (&mem_mutex);
267 #else
268 pthread_mutex_unlock (&mem_mutex);
269 #endif
270 return NULL;
273 memcpy (p, m->ptr, size < m->size ? size : m->size);
274 memzero (m->ptr, m->size);
275 free (m->ptr);
276 m->ptr = p;
277 m->size = size;
278 #ifdef DEBUG
279 fprintf (stderr, "%s: %p %i\n", __FUNCTION__, p, size);
280 BACKTRACE (__FUNCTION__);
281 #endif
282 #ifdef USE_PTH_THREADS
283 pth_mutex_release (&mem_mutex);
284 #else
285 pthread_mutex_unlock (&mem_mutex);
286 #endif
287 return m->ptr;
291 warnx (_("%s: %p not found"), __FUNCTION__, ptr);
292 #ifdef USE_PTH_THREADS
293 pth_mutex_release (&mem_mutex);
294 #else
295 pthread_mutex_unlock (&mem_mutex);
296 #endif
297 assert (0);
298 return NULL;
301 void
302 xpanic (void)
304 struct memlist_s *m;
306 #ifdef USE_PTH_THREADS
307 pth_mutex_acquire (&mem_mutex, 0, NULL);
308 #else
309 pthread_mutex_lock (&mem_mutex);
310 #endif
312 for (m = memlist; m; m = memlist)
313 xfree (m->ptr);
315 #ifdef USE_PTH_THREADS
316 pth_mutex_release (&mem_mutex);
317 #else
318 pthread_mutex_unlock (&mem_mutex);
319 #endif
322 #ifdef DEBUG
323 void
324 xdump (void)
326 struct memlist_s *m;
327 size_t total = 0;
329 #ifdef USE_PTH_THREADS
330 pth_mutex_acquire (&mem_mutex, 0, NULL);
331 #else
332 pthread_mutex_lock (&mem_mutex);
333 #endif
335 for (m = memlist; m; m = m->next)
337 fprintf (stderr, "%s: %p %i\n", __FUNCTION__, m->ptr, m->size);
338 total += m->size;
341 fprintf (stderr,
342 "Total unfreed: %i bytes, allocations: %i, deallocations: %i\n",
343 total, allocations, deallocations);
344 #ifdef USE_PTH_THREADS
345 pth_mutex_release (&mem_mutex);
346 #else
347 pthread_mutex_unlock (&mem_mutex);
348 #endif
350 #endif