Version 3.0.12.
[pwmd.git] / src / mem.c
blob963163df2bcc7d39760b70e8feb7840653d97a2f
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
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>
30 #include <pthread.h>
32 #include "memzero.h"
34 #ifndef _
35 #include "gettext.h"
36 #define _(msgid) gettext(msgid)
37 #endif
39 #ifdef DEBUG
40 #ifdef HAVE_BACKTRACE
41 #include <execinfo.h>
43 #ifndef BACKTRACE
44 #define BACKTRACE(fn) { \
45 int n, nptrs; \
46 char **strings; \
47 void *buffer[20]; \
48 nptrs = backtrace(buffer, 20); \
49 strings = backtrace_symbols(buffer, nptrs); \
50 for (n = 0; n < nptrs; n++) \
51 fprintf(stderr, "BACKTRACE (%s) %i: %s\n", fn, n, strings[n]); \
52 fprintf(stderr, "\n"); \
53 fflush(stderr); \
55 #endif
56 #endif
57 #else
58 #define BACKTRACE(fn)
59 #endif
61 #include "mem.h"
63 #ifndef _
64 #define _ gettext(msgid)
65 #endif
67 struct memlist_s
69 void *ptr;
70 size_t size;
71 struct memlist_s *next;
74 static struct memlist_s *memlist;
75 static pthread_mutex_t mem_mutex;
76 #ifdef DEBUG
77 static size_t allocations, deallocations;
78 #endif
80 void
81 xmem_init ()
83 static int init;
85 if (!init)
86 pthread_mutex_init (&mem_mutex, NULL);
88 init = 1;
91 static int
92 memlist_remove (void *ptr, const char *func)
94 struct memlist_s *m, *last = NULL, *p;
96 pthread_mutex_lock (&mem_mutex);
98 for (m = memlist; m; m = m->next)
100 if (m->ptr == ptr)
102 #ifdef DEBUG
103 fprintf (stderr, "%s: %p %i\n", func, ptr, m->size);
104 #endif
105 memzero (m->ptr, m->size);
106 free (m->ptr);
108 p = m->next;
109 free (m);
110 #ifdef DEBUG
111 deallocations++;
112 #endif
114 if (last)
115 last->next = p;
116 else
117 memlist = p;
119 pthread_mutex_unlock (&mem_mutex);
120 return 1;
123 last = m;
126 pthread_mutex_unlock (&mem_mutex);
127 return 0;
130 static void
131 memlist_prepend (struct memlist_s *new)
133 pthread_mutex_lock (&mem_mutex);
134 #ifdef DEBUG
135 allocations++;
136 #endif
137 new->next = memlist;
138 memlist = new;
139 pthread_mutex_unlock (&mem_mutex);
142 void
143 xfree (void *ptr)
145 if (!ptr)
146 return;
148 if (!memlist_remove (ptr, __FUNCTION__))
150 warnx (_("%s: %p not found"), __FUNCTION__, ptr);
151 assert (0);
155 void *
156 xmalloc (size_t size)
158 void *p;
159 struct memlist_s *m;
161 if ((m = (struct memlist_s *) malloc (sizeof (struct memlist_s))) == NULL)
162 return NULL;
164 if ((p = (void *) malloc (size)) == NULL)
166 free (m);
167 return NULL;
170 m->ptr = p;
171 m->size = size;
172 memlist_prepend (m);
173 #ifdef DEBUG
174 fprintf (stderr, "%s: %p %u\n", __FUNCTION__, p, size);
175 BACKTRACE (__FUNCTION__);
176 #endif
177 return m->ptr;
180 void *
181 xcalloc (size_t nmemb, size_t size)
183 void *p;
184 struct memlist_s *m;
186 if ((m = (struct memlist_s *) malloc (sizeof (struct memlist_s))) == NULL)
187 return NULL;
189 if ((p = calloc (nmemb, size)) == NULL)
191 free (m);
192 return NULL;
195 m->ptr = p;
196 m->size = nmemb * size;
197 memlist_prepend (m);
198 #ifdef DEBUG
199 fprintf (stderr, "%s: %p %i\n", __FUNCTION__, p, nmemb * size);
200 BACKTRACE (__FUNCTION__);
201 #endif
202 return m->ptr;
205 void *
206 xrealloc (void *ptr, size_t size)
208 void *p;
209 struct memlist_s *m;
211 if (!size && ptr)
213 xfree (ptr);
214 return NULL;
217 if (!ptr)
218 return xmalloc (size);
220 pthread_mutex_lock (&mem_mutex);
222 for (m = memlist; m; m = m->next)
224 if (m->ptr == ptr)
226 if ((p = (void *) malloc (size)) == NULL)
228 pthread_mutex_unlock (&mem_mutex);
229 return NULL;
232 memcpy (p, m->ptr, size < m->size ? size : m->size);
233 memzero (m->ptr, m->size);
234 free (m->ptr);
235 m->ptr = p;
236 m->size = size;
237 #ifdef DEBUG
238 fprintf (stderr, "%s: %p %u\n", __FUNCTION__, p, size);
239 BACKTRACE (__FUNCTION__);
240 #endif
241 pthread_mutex_unlock (&mem_mutex);
242 return m->ptr;
246 warnx (_("%s: %p not found"), __FUNCTION__, ptr);
247 pthread_mutex_unlock (&mem_mutex);
248 assert (0);
249 return NULL;
252 void
253 xpanic (void)
255 struct memlist_s *m;
257 pthread_mutex_lock (&mem_mutex);
259 for (m = memlist; m; m = memlist)
260 xfree (m->ptr);
262 pthread_mutex_unlock (&mem_mutex);
265 #ifdef DEBUG
266 void
267 xdump (void)
269 struct memlist_s *m;
270 size_t total = 0;
272 pthread_mutex_lock (&mem_mutex);
274 for (m = memlist; m; m = m->next)
276 fprintf (stderr, "%s: %p %u\n", __FUNCTION__, m->ptr, m->size);
277 total += m->size;
280 fprintf (stderr,
281 "Total unfreed: %u bytes, allocations: %u, deallocations: %u\n",
282 total, allocations, deallocations);
283 pthread_mutex_unlock (&mem_mutex);
285 #endif