Add to git.
[c2lib.git] / test_pool.c
1 /* Test pools, subpools, memory allocation and so on.
2  * By Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: test_pool.c,v 1.5 2002/12/07 15:18:26 rich Exp $
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <errno.h>
27
28 /* Implement a simple malloc debugger -- which counts allocations and
29  * frees and ensures that all memory allocated by the pool code is
30  * evenually freed.
31  */
32
33 static void  trace_init (void);
34 static void  trace_finish (void);
35 static void *trace_malloc (size_t n, const char *filename, int line);
36 static void *trace_realloc (void *p, size_t n, const char *filename, int line);
37 static void  trace_free (void *p);
38
39 #define malloc(n)    trace_malloc ((n), __FILE__, __LINE__);
40 #define realloc(p,n) trace_realloc ((p), (n), __FILE__, __LINE__);
41 #define free(p)      trace_free ((p));
42
43 #define NO_GLOBAL_POOL 1
44
45 #include "pool.h"
46 #include "pool.c"
47
48 static void test (void);
49
50 int
51 main ()
52 {
53   trace_init ();
54   test ();
55   trace_finish ();
56   exit (0);
57 }
58
59 /* Perform the tests. */
60 static void
61 simple_alloc_test ()
62 {
63   pool p;
64   int i;
65
66   p = new_pool ();
67
68   for (i = 0; i < 1000; ++i)
69     {
70       pmalloc (p, 1);
71       pmalloc (p, 1);
72       prealloc (p, pmalloc (p, 200), 300);
73       pmalloc (p, 1000);
74       prealloc (p, pmalloc (p, 1000), 1001);
75       prealloc (p, pmalloc (p, 900), 901);
76       pmalloc (p, 1);
77       pmalloc (p, 4);
78       pmalloc (p, 8);
79       pmalloc (p, 1);
80       pmalloc (p, 400);
81     }
82
83   delete_pool (p);
84 }
85
86 static void
87 simple_subpool_test (pool parent, int level)
88 {
89   pool p;
90   int i;
91
92   if (level >= 8) return;
93
94   if (parent)
95     {
96       /* The following two statements must remain together. */
97       p = new_subpool (parent);
98       prealloc (p, prealloc (p, pmalloc (p, 16), 100),
99                 200);
100       /* End of realloc test. */
101
102       pcalloc (p, 4, 4);
103       prealloc (p, 0, 8);
104       prealloc (p, pmalloc (p, 4), 8);
105       pmalloc (parent, 1);
106       prealloc (parent, pmalloc (parent, 8), 8);
107       prealloc (parent, pmalloc (parent, 8), 16);
108     }
109   else
110     {
111       p = new_pool ();
112       prealloc (p, pmalloc (p, 4), 8);
113       pmalloc (p, 8);
114       pmalloc (p, 1);
115     }
116
117   for (i = 0; i < 3; ++i)
118     {
119       simple_subpool_test (p, level+1);
120       pmalloc (p, 1);
121       if (parent) pmalloc (parent, 1);
122     }
123
124   if (parent == 0 || level == 4)
125     delete_pool (p);
126 }
127
128 /* This is a regression test: we had reason to believe this didn't work
129  * at one point.
130  */
131 static void
132 create_delete_test ()
133 {
134   pool p;
135
136   p = new_pool ();
137   delete_pool (p);
138 }
139
140 static int cleanup_called = 0;
141
142 static void
143 cleanup_fn (void *v)
144 {
145   cleanup_called ++;
146 }
147
148 static void
149 cleanup_fn_test ()
150 {
151   pool p, sp1, sp2;
152
153   p = new_pool ();
154   pool_register_cleanup_fn (p, cleanup_fn, 0);
155   delete_pool (p);
156   assert (cleanup_called == 1);
157
158   p = new_pool ();
159   sp1 = new_subpool (p);
160   sp2 = new_subpool (p);
161   pool_register_cleanup_fn (p, cleanup_fn, 0);
162   pool_register_cleanup_fn (sp1, cleanup_fn, 0);
163   pool_register_cleanup_fn (sp2, cleanup_fn, 0);
164   delete_pool (sp1);
165   assert (cleanup_called == 2);
166   delete_pool (p);
167   assert (cleanup_called == 4);
168 }
169
170 static void
171 cleanup_fd_test ()
172 {
173   int fd;
174   pool p;
175
176   p = new_pool ();
177   fd = open ("/dev/null", O_RDONLY);
178   pool_register_fd (p, fd);
179   delete_pool (p);
180
181   assert (close (fd) == -1 && errno == EBADF);
182 }
183
184 static void
185 cleanup_malloc_test ()
186 {
187   void *m;
188   pool p;
189
190   p = new_pool ();
191   m = malloc (10);
192   pool_register_malloc (p, m);
193   delete_pool (p);
194 }
195
196 static void
197 lots_of_pmalloc_test ()
198 {
199   pool p;
200   pool *subpools;
201   int i, j, np = 0;
202
203   /* This test kind of simulates what the chat server does, in an
204    * attempt to find the putative memory leak.
205    */
206   p = new_pool ();
207   subpools = pcalloc (p, sizeof (struct pool), 100);
208
209   for (i = 0; i < 10000; ++i)
210     {
211       if (subpools[np] != 0)
212         delete_pool (subpools[np]);
213       subpools[np] = new_subpool (p);
214
215       for (j = 0; j < 100; ++j)
216         {
217           void *ptr = pmalloc (subpools[np], 100);
218           prealloc (subpools[np], ptr, 200);
219         }
220
221       np++;
222       if (np == 100) np = 0;
223     }
224
225   delete_pool (p);
226 }
227
228 static void
229 test ()
230 {
231   simple_alloc_test ();
232   simple_subpool_test (0, 0);
233   create_delete_test ();
234   cleanup_fn_test ();
235   cleanup_fd_test ();
236   cleanup_malloc_test ();
237   lots_of_pmalloc_test ();
238 }
239
240 /* The tracing code. */
241 #undef malloc
242 #undef realloc
243 #undef free
244
245 static int nr_allocations = 0;
246
247 static void
248 trace_init ()
249 {
250 }
251
252 static void
253 trace_finish ()
254 {
255   if (nr_allocations > 0)
256     {
257       fprintf (stderr, "*** error: %d allocation(s) leaked.\n",
258                nr_allocations);
259       exit (1);
260     }
261 }
262
263 static void *
264 trace_malloc (size_t n, const char *filename, int line)
265 {
266   nr_allocations++;
267   return malloc (n);
268 }
269
270 static void *
271 trace_realloc (void *p, size_t n, const char *filename, int line)
272 {
273   return realloc (p, n);
274 }
275
276 static void
277 trace_free (void *p)
278 {
279   nr_allocations--;
280   free (p);
281 }