Create a mutex for the custom memory functions. Fixes list corruption.
[pwmd.git] / src / mem.c
blob152b0ecbe02b7b0ad083e446bdd948d5146e6874
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <err.h>
25 #include <pthread.h>
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include "gettext.h"
32 #define N_(msgid) gettext(msgid)
34 #include "mem.h"
36 static struct memlist_s *memlist;
37 static pthread_mutex_t mem_mutex;
38 #ifdef DEBUG
39 static size_t allocations, deallocations;
40 #endif
42 void xmem_init()
44 static int init;
46 if (!init)
47 pthread_mutex_init(&mem_mutex, NULL);
49 init = 1;
52 void xmem_deinit()
54 pthread_mutex_destroy(&mem_mutex);
57 static int memlist_remove(void *ptr, const char *func)
59 struct memlist_s *m, *last = NULL, *p;
60 int found = 0;
62 for (m = memlist; m; m = m->next) {
63 if (m->ptr == ptr) {
64 #ifdef DEBUG
65 fprintf(stderr, "%s: %p %i\n", func, ptr, m->size);
66 #endif
67 found = 1;
68 memset(m->ptr, 0, m->size);
69 free(m->ptr);
71 p = m->next;
72 free(m);
73 #ifdef DEBUG
74 deallocations++;
75 #endif
77 if (last) {
78 if (p)
79 last->next = p;
80 else
81 last->next = NULL;
83 else if (p)
84 memlist = p;
85 else
86 memlist = NULL;
88 break;
91 last = m;
94 return found;
97 static void memlist_prepend(struct memlist_s *new)
99 #ifdef DEBUG
100 allocations++;
101 #endif
102 new->next = memlist;
103 memlist = new;
106 void xfree(void *ptr)
108 pthread_mutex_lock(&mem_mutex);
110 if (!ptr) {
111 pthread_mutex_unlock(&mem_mutex);
112 return;
115 if (!memlist_remove(ptr, __FUNCTION__)) {
116 warnx(N_("%s: %p not found"), __FUNCTION__, ptr);
117 pthread_mutex_unlock(&mem_mutex);
118 assert(0);
121 pthread_mutex_unlock(&mem_mutex);
124 void *xmalloc(size_t size)
126 void *p;
127 struct memlist_s *m;
129 pthread_mutex_lock(&mem_mutex);
131 if (size <= 0) {
132 pthread_mutex_unlock(&mem_mutex);
133 return NULL;
136 if ((m = (struct memlist_s *)malloc(sizeof(struct memlist_s))) == NULL) {
137 pthread_mutex_unlock(&mem_mutex);
138 return NULL;
141 if ((p = (void *)malloc(size)) == NULL) {
142 free(m);
143 pthread_mutex_unlock(&mem_mutex);
144 return NULL;
147 m->ptr = p;
148 m->size = size;
149 memlist_prepend(m);
150 #ifdef DEBUG
151 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, p, size);
152 #endif
153 pthread_mutex_unlock(&mem_mutex);
154 return m->ptr;
157 void *xcalloc(size_t nmemb, size_t size)
159 void *p;
160 struct memlist_s *m;
162 pthread_mutex_lock(&mem_mutex);
164 if (size <= 0) {
165 pthread_mutex_unlock(&mem_mutex);
166 return NULL;
169 if ((m = (struct memlist_s *)malloc(sizeof(struct memlist_s))) == NULL) {
170 pthread_mutex_unlock(&mem_mutex);
171 return NULL;
174 if ((p = calloc(nmemb, size)) == NULL) {
175 free(m);
176 pthread_mutex_unlock(&mem_mutex);
177 return NULL;
180 m->ptr = p;
181 m->size = nmemb * size;
182 memlist_prepend(m);
183 #ifdef DEBUG
184 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, p, nmemb * size);
185 #endif
186 pthread_mutex_unlock(&mem_mutex);
187 return m->ptr;
190 void *xrealloc(void *ptr, size_t size)
192 void *p;
193 struct memlist_s *m;
195 if (size <= 0)
196 return ptr;
198 if (!ptr)
199 return xmalloc(size);
201 pthread_mutex_lock(&mem_mutex);
203 for (m = memlist; m; m = m->next) {
204 if (m->ptr == ptr) {
205 if ((p = (void *)malloc(size)) == NULL) {
206 pthread_mutex_unlock(&mem_mutex);
207 return NULL;
210 memcpy(p, m->ptr, size < m->size ? size : m->size);
211 memset(m->ptr, 0, m->size);
212 free(m->ptr);
213 m->ptr = p;
214 m->size = size;
215 #ifdef DEBUG
216 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, p, size);
217 #endif
218 pthread_mutex_unlock(&mem_mutex);
219 return m->ptr;
223 warnx(N_("%s: %p not found"), __FUNCTION__, ptr);
224 pthread_mutex_unlock(&mem_mutex);
225 assert(0);
226 return NULL;
229 char *xstrdup(const char *str)
231 char *t, *tp;
232 size_t len;
233 const char *p;
235 if (!str)
236 return NULL;
238 len = strlen(str) + 1;
240 if ((t = (char *)xmalloc(len * sizeof(char))) == NULL)
241 return NULL;
243 for (p = str, tp = t; *p; p++)
244 *tp++ = *p;
246 *tp = 0;
247 #ifdef DEBUG
248 fprintf(stderr, "%s: %p\n", __FUNCTION__, t);
249 #endif
250 return t;
253 void 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 xdump(void)
268 struct memlist_s *m;
269 size_t total = 0;
271 pthread_mutex_lock(&mem_mutex);
273 for (m = memlist; m; m = m->next) {
274 fprintf(stderr, "%s: %p %i\n", __FUNCTION__, m->ptr, m->size);
275 total += m->size;
278 fprintf(stderr, "Total unfreed: %i bytes, allocations: %i, deallocations: %i\n", total,
279 allocations, deallocations);
280 pthread_mutex_unlock(&mem_mutex);
282 #endif