- removed strongswan includes, we are now self-contained ;-)
[strongswan.git] / Source / charon / allocator.c
1 /**
2 * @file allocator.c
3 *
4 * @brief Memory allocation with LEAK_DETECTION support
5 *
6 * Thread-save implementation
7 */
8
9 /*
10 * Copyright (C) 2005 Jan Hutter, Martin Willi
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <pthread.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <stdio.h>
30
31 #ifndef ALLOCATOR_C_
32 #define ALLOCATOR_C_
33 #endif
34
35 #include "allocator.h"
36
37 #ifdef LEAK_DETECTIVE
38
39 /**
40 * Header of each allocated memory area
41 *
42 * Used to detect memory leaks
43 */
44 typedef union memory_hdr_u memory_hdr_t;
45
46 union memory_hdr_u {
47 struct {
48 /**
49 * Filename withing memory was allocated
50 */
51 const char *filename;
52 /**
53 * Line number in given file
54 */
55 size_t line;
56 /**
57 * Allocated memory size. Needed for reallocation
58 */
59 size_t size_of_memory;
60 /**
61 * Link to the previous and next memory area
62 */
63 memory_hdr_t *older, *newer;
64 } info; /* info */
65 /**
66 * force maximal alignment ?
67 */
68 unsigned long junk;
69 };
70
71 /**
72 * @brief Private allocator_t object.
73 *
74 * Contains private variables of allocator_t object.
75 */
76 typedef struct private_allocator_s private_allocator_t;
77
78 struct private_allocator_s
79 {
80 /**
81 * Public part of an allocator_t object.
82 */
83 allocator_t public;
84
85 /**
86 * Global list of allocations
87 *
88 * Thread-save through mutex
89 */
90 memory_hdr_t *allocations;
91
92 /**
93 * Mutex used to make sure, all functions are thread-save
94 */
95 pthread_mutex_t mutex;
96 };
97
98
99 /**
100 * Implements allocator_t's function allocate.
101 * See #allocator_s.allocate for description.
102 */
103 static void * allocate(allocator_t *allocator,size_t bytes, char * file,int line)
104 {
105 private_allocator_t *this = (private_allocator_t *) allocator;
106 memory_hdr_t *allocated_memory = malloc(sizeof(memory_hdr_t) + bytes);
107
108 if (allocated_memory == NULL)
109 {
110 return allocated_memory;
111 }
112
113 pthread_mutex_lock( &(this->mutex));
114
115 allocated_memory->info.line = line;
116 allocated_memory->info.filename = file;
117 allocated_memory->info.size_of_memory = bytes;
118 allocated_memory->info.older = this->allocations;
119 if (this->allocations != NULL)
120 {
121 this->allocations->info.newer = allocated_memory;
122 }
123 this->allocations = allocated_memory;
124 allocated_memory->info.newer = NULL;
125
126 /* fill memory with zero's */
127 memset(allocated_memory+1, '\0', bytes);
128 pthread_mutex_unlock(&(this->mutex));
129 /* real memory starts after header */
130 return (allocated_memory+1);
131 }
132
133 /*
134 * Implements allocator_t's free_pointer allocate.
135 * See #allocator_s.free_pointer for description.
136 */
137 static void free_pointer(allocator_t *allocator, void * pointer)
138 {
139 private_allocator_t *this = (private_allocator_t *) allocator;
140 memory_hdr_t *allocated_memory;
141
142 if (pointer == NULL)
143 {
144 return;
145 }
146 pthread_mutex_lock( &(this->mutex));
147 allocated_memory = ((memory_hdr_t *)pointer) - 1;
148
149 if (allocated_memory->info.older != NULL)
150 {
151 assert(allocated_memory->info.older->info.newer == allocated_memory);
152 allocated_memory->info.older->info.newer = allocated_memory->info.newer;
153 }
154 if (allocated_memory->info.newer == NULL)
155 {
156 assert(allocated_memory == this->allocations);
157 this->allocations = allocated_memory->info.older;
158 }
159 else
160 {
161 assert(allocated_memory->info.newer->info.older == allocated_memory);
162 allocated_memory->info.newer->info.older = allocated_memory->info.older;
163 }
164 pthread_mutex_unlock(&(this->mutex));
165 free(allocated_memory);
166 }
167
168 /*
169 * Implements allocator_t's reallocate allocate.
170 * See #allocator_s.reallocate for description.
171 */
172 static void * reallocate(allocator_t *allocator, void * old, size_t bytes, char * file,int line)
173 {
174 private_allocator_t *this = (private_allocator_t *) allocator;
175 memory_hdr_t *allocated_memory;
176
177 if (old == NULL)
178 {
179 return NULL;
180 }
181 pthread_mutex_lock( &(this->mutex));
182 allocated_memory = ((memory_hdr_t *)old) - 1;
183
184 void *new_space = this->public.allocate(&(this->public),bytes,file,line);
185 if (new_space == NULL)
186 {
187 this->public.free_pointer(&(this->public),old);
188 pthread_mutex_unlock(&(this->mutex));
189 return NULL;
190 }
191
192 memcpy(new_space,old,allocated_memory->info.size_of_memory);
193 pthread_mutex_unlock(&(this->mutex));
194
195 return new_space;
196 }
197
198 /*
199 * Implements allocator_t's report_memory_leaks allocate.
200 * See #allocator_s.report_memory_leaks for description.
201 */
202 static void allocator_report_memory_leaks(allocator_t *allocator)
203 {
204 private_allocator_t *this = (private_allocator_t *) allocator;
205 memory_hdr_t *p = this->allocations;
206 memory_hdr_t *pprev = NULL;
207 unsigned long n = 0;
208
209 pthread_mutex_lock(&(this->mutex));
210
211 while (p != NULL)
212 {
213 assert(pprev == p->info.newer);
214 pprev = p;
215 p = p->info.older;
216 n++;
217 if (p == NULL || pprev->info.filename != p->info.filename)
218 {
219 if (n != 1)
220 fprintf(stderr,"LEAK: \"%lu * File %s, Line %d\"\n", n, pprev->info.filename,pprev->info.line);
221 else
222 fprintf(stderr,"LEAK: \"%s, Line %d\"\n", pprev->info.filename,pprev->info.line);
223 n = 0;
224 }
225 }
226 pthread_mutex_unlock( &(this->mutex));
227 }
228
229 /**
230 * Only initiation of allocator object.
231 *
232 * All allocation macros use this object.
233 */
234 static private_allocator_t allocator = {
235 public: {allocate: allocate,
236 free_pointer: free_pointer,
237 reallocate: reallocate,
238 report_memory_leaks: allocator_report_memory_leaks},
239 allocations: NULL,
240 mutex: PTHREAD_MUTEX_INITIALIZER
241 };
242
243
244
245 allocator_t *global_allocator = &(allocator.public);
246 #endif