Default kdump's data limit to 64 bytes and document how it can be disabled.
[dragonfly.git] / contrib / sendmail-8.13.7 / libsm / rpool.c
1 /*
2  * Copyright (c) 2000-2004 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  */
9
10 #include <sm/gen.h>
11 SM_RCSID("@(#)$Id: rpool.c,v 1.28 2004/08/03 20:44:04 ca Exp $")
12
13 /*
14 **  resource pools
15 **  For documentation, see rpool.html
16 */
17
18 #include <sm/exc.h>
19 #include <sm/heap.h>
20 #include <sm/rpool.h>
21 #include <sm/varargs.h>
22 #include <sm/conf.h>
23 #if _FFR_PERF_RPOOL
24 # include <syslog.h>
25 #endif /* _FFR_PERF_RPOOL */
26
27 const char SmRpoolMagic[] = "sm_rpool";
28
29 typedef union
30 {
31         SM_POOLLINK_T   link;
32         char            align[SM_ALIGN_SIZE];
33 } SM_POOLHDR_T;
34
35 static char     *sm_rpool_allocblock_x __P((SM_RPOOL_T *, size_t));
36 static char     *sm_rpool_allocblock __P((SM_RPOOL_T *, size_t));
37
38 /*
39 **  Tune this later
40 */
41
42 #define POOLSIZE                4096
43 #define BIG_OBJECT_RATIO        10
44
45 /*
46 **  SM_RPOOL_ALLOCBLOCK_X -- allocate a new block for an rpool.
47 **
48 **      Parameters:
49 **              rpool -- rpool to which the block should be added.
50 **              size -- size of block.
51 **
52 **      Returns:
53 **              Pointer to block.
54 **
55 **      Exceptions:
56 **              F:sm_heap -- out of memory
57 */
58
59 static char *
60 sm_rpool_allocblock_x(rpool, size)
61         SM_RPOOL_T *rpool;
62         size_t size;
63 {
64         SM_POOLLINK_T *p;
65
66         p = sm_malloc_x(sizeof(SM_POOLHDR_T) + size);
67         p->sm_pnext = rpool->sm_pools;
68         rpool->sm_pools = p;
69         return (char*) p + sizeof(SM_POOLHDR_T);
70 }
71
72 /*
73 **  SM_RPOOL_ALLOCBLOCK -- allocate a new block for an rpool.
74 **
75 **      Parameters:
76 **              rpool -- rpool to which the block should be added.
77 **              size -- size of block.
78 **
79 **      Returns:
80 **              Pointer to block, NULL on failure.
81 */
82
83 static char *
84 sm_rpool_allocblock(rpool, size)
85         SM_RPOOL_T *rpool;
86         size_t size;
87 {
88         SM_POOLLINK_T *p;
89
90         p = sm_malloc(sizeof(SM_POOLHDR_T) + size);
91         if (p == NULL)
92                 return NULL;
93         p->sm_pnext = rpool->sm_pools;
94         rpool->sm_pools = p;
95         return (char*) p + sizeof(SM_POOLHDR_T);
96 }
97
98 /*
99 **  SM_RPOOL_MALLOC_TAGGED_X -- allocate memory from rpool
100 **
101 **      Parameters:
102 **              rpool -- rpool from which memory should be allocated;
103 **                      can be NULL, use sm_malloc() then.
104 **              size -- size of block.
105 **              file -- filename.
106 **              line -- line number in file.
107 **              group -- heap group for debugging.
108 **
109 **      Returns:
110 **              Pointer to block.
111 **
112 **      Exceptions:
113 **              F:sm_heap -- out of memory
114 **
115 **      Notice: XXX
116 **              if size == 0 and the rpool is new (no memory
117 **              allocated yet) NULL is returned!
118 **              We could solve this by
119 **              - wasting 1 byte (size < avail)
120 **              - checking for rpool->sm_poolptr != NULL
121 **              - not asking for 0 sized buffer
122 */
123
124 void *
125 #if SM_HEAP_CHECK
126 sm_rpool_malloc_tagged_x(rpool, size, file, line, group)
127         SM_RPOOL_T *rpool;
128         size_t size;
129         char *file;
130         int line;
131         int group;
132 #else /* SM_HEAP_CHECK */
133 sm_rpool_malloc_x(rpool, size)
134         SM_RPOOL_T *rpool;
135         size_t size;
136 #endif /* SM_HEAP_CHECK */
137 {
138         char *ptr;
139
140         if (rpool == NULL)
141                 return sm_malloc_tagged_x(size, file, line, group);
142
143         /* Ensure that size is properly aligned. */
144         if (size & SM_ALIGN_BITS)
145                 size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
146
147         /* The common case.  This is optimized for speed. */
148         if (size <= rpool->sm_poolavail)
149         {
150                 ptr = rpool->sm_poolptr;
151                 rpool->sm_poolptr += size;
152                 rpool->sm_poolavail -= size;
153                 return ptr;
154         }
155
156         /*
157         **  The slow case: we need to call malloc.
158         **  The SM_REQUIRE assertion is deferred until now, for speed.
159         **  That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
160         **  so the common case code won't be triggered on a dangling pointer.
161         */
162
163         SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
164
165         /*
166         **  If size > sm_poolsize, then malloc a new block especially for
167         **  this request.  Future requests will be allocated from the
168         **  current pool.
169         **
170         **  What if the current pool is mostly unallocated, and the current
171         **  request is larger than the available space, but < sm_poolsize?
172         **  If we discard the current pool, and start allocating from a new
173         **  pool, then we will be wasting a lot of space.  For this reason,
174         **  we malloc a block just for the current request if size >
175         **  sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
176         **  Thus, the most space that we will waste at the end of a pool
177         **  is sm_bigobjectsize - 1.
178         */
179
180         if (size > rpool->sm_bigobjectsize)
181         {
182 #if _FFR_PERF_RPOOL
183                 ++rpool->sm_nbigblocks;
184 #endif /* _FFR_PERF_RPOOL */
185                 return sm_rpool_allocblock_x(rpool, size);
186         }
187         SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
188         ptr = sm_rpool_allocblock_x(rpool, rpool->sm_poolsize);
189         rpool->sm_poolptr = ptr + size;
190         rpool->sm_poolavail = rpool->sm_poolsize - size;
191 #if _FFR_PERF_RPOOL
192         ++rpool->sm_npools;
193 #endif /* _FFR_PERF_RPOOL */
194         return ptr;
195 }
196
197 /*
198 **  SM_RPOOL_MALLOC_TAGGED -- allocate memory from rpool
199 **
200 **      Parameters:
201 **              rpool -- rpool from which memory should be allocated;
202 **                      can be NULL, use sm_malloc() then.
203 **              size -- size of block.
204 **              file -- filename.
205 **              line -- line number in file.
206 **              group -- heap group for debugging.
207 **
208 **      Returns:
209 **              Pointer to block, NULL on failure.
210 **
211 **      Notice: XXX
212 **              if size == 0 and the rpool is new (no memory
213 **              allocated yet) NULL is returned!
214 **              We could solve this by
215 **              - wasting 1 byte (size < avail)
216 **              - checking for rpool->sm_poolptr != NULL
217 **              - not asking for 0 sized buffer
218 */
219
220 void *
221 #if SM_HEAP_CHECK
222 sm_rpool_malloc_tagged(rpool, size, file, line, group)
223         SM_RPOOL_T *rpool;
224         size_t size;
225         char *file;
226         int line;
227         int group;
228 #else /* SM_HEAP_CHECK */
229 sm_rpool_malloc(rpool, size)
230         SM_RPOOL_T *rpool;
231         size_t size;
232 #endif /* SM_HEAP_CHECK */
233 {
234         char *ptr;
235
236         if (rpool == NULL)
237                 return sm_malloc_tagged(size, file, line, group);
238
239         /* Ensure that size is properly aligned. */
240         if (size & SM_ALIGN_BITS)
241                 size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
242
243         /* The common case.  This is optimized for speed. */
244         if (size <= rpool->sm_poolavail)
245         {
246                 ptr = rpool->sm_poolptr;
247                 rpool->sm_poolptr += size;
248                 rpool->sm_poolavail -= size;
249                 return ptr;
250         }
251
252         /*
253         **  The slow case: we need to call malloc.
254         **  The SM_REQUIRE assertion is deferred until now, for speed.
255         **  That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
256         **  so the common case code won't be triggered on a dangling pointer.
257         */
258
259         SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
260
261         /*
262         **  If size > sm_poolsize, then malloc a new block especially for
263         **  this request.  Future requests will be allocated from the
264         **  current pool.
265         **
266         **  What if the current pool is mostly unallocated, and the current
267         **  request is larger than the available space, but < sm_poolsize?
268         **  If we discard the current pool, and start allocating from a new
269         **  pool, then we will be wasting a lot of space.  For this reason,
270         **  we malloc a block just for the current request if size >
271         **  sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
272         **  Thus, the most space that we will waste at the end of a pool
273         **  is sm_bigobjectsize - 1.
274         */
275
276         if (size > rpool->sm_bigobjectsize)
277         {
278 #if _FFR_PERF_RPOOL
279                 ++rpool->sm_nbigblocks;
280 #endif /* _FFR_PERF_RPOOL */
281                 return sm_rpool_allocblock(rpool, size);
282         }
283         SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
284         ptr = sm_rpool_allocblock(rpool, rpool->sm_poolsize);
285         if (ptr == NULL)
286                 return NULL;
287         rpool->sm_poolptr = ptr + size;
288         rpool->sm_poolavail = rpool->sm_poolsize - size;
289 #if _FFR_PERF_RPOOL
290         ++rpool->sm_npools;
291 #endif /* _FFR_PERF_RPOOL */
292         return ptr;
293 }
294
295 /*
296 **  SM_RPOOL_NEW_X -- create a new rpool.
297 **
298 **      Parameters:
299 **              parent -- pointer to parent rpool, can be NULL.
300 **
301 **      Returns:
302 **              Pointer to new rpool.
303 */
304
305 SM_RPOOL_T *
306 sm_rpool_new_x(parent)
307         SM_RPOOL_T *parent;
308 {
309         SM_RPOOL_T *rpool;
310
311         rpool = sm_malloc_x(sizeof(SM_RPOOL_T));
312         if (parent == NULL)
313                 rpool->sm_parentlink = NULL;
314         else
315         {
316                 SM_TRY
317                         rpool->sm_parentlink = sm_rpool_attach_x(parent,
318                                         (SM_RPOOL_RFREE_T) sm_rpool_free,
319                                         (void *) rpool);
320                 SM_EXCEPT(exc, "*")
321                         sm_free(rpool);
322                         sm_exc_raise_x(exc);
323                 SM_END_TRY
324         }
325         rpool->sm_magic = SmRpoolMagic;
326
327         rpool->sm_poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
328         rpool->sm_bigobjectsize = rpool->sm_poolsize / BIG_OBJECT_RATIO;
329         rpool->sm_poolptr = NULL;
330         rpool->sm_poolavail = 0;
331         rpool->sm_pools = NULL;
332
333         rpool->sm_rptr = NULL;
334         rpool->sm_ravail = 0;
335         rpool->sm_rlists = NULL;
336 #if _FFR_PERF_RPOOL
337         rpool->sm_nbigblocks = 0;
338         rpool->sm_npools = 0;
339 #endif /* _FFR_PERF_RPOOL */
340
341         return rpool;
342 }
343
344 /*
345 **  SM_RPOOL_SETSIZES -- set sizes for rpool.
346 **
347 **      Parameters:
348 **              poolsize -- size of a single rpool block.
349 **              bigobjectsize -- if this size is exceeded, an individual
350 **                      block is allocated (must be less or equal poolsize).
351 **
352 **      Returns:
353 **              none.
354 */
355
356 void
357 sm_rpool_setsizes(rpool, poolsize, bigobjectsize)
358         SM_RPOOL_T *rpool;
359         size_t poolsize;
360         size_t bigobjectsize;
361 {
362         SM_REQUIRE(poolsize >= bigobjectsize);
363         if (poolsize == 0)
364                 poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
365         if (bigobjectsize == 0)
366                 bigobjectsize = poolsize / BIG_OBJECT_RATIO;
367         rpool->sm_poolsize = poolsize;
368         rpool->sm_bigobjectsize = bigobjectsize;
369 }
370
371 /*
372 **  SM_RPOOL_FREE -- free an rpool and release all of its resources.
373 **
374 **      Parameters:
375 **              rpool -- rpool to free.
376 **
377 **      Returns:
378 **              none.
379 */
380
381 void
382 sm_rpool_free(rpool)
383         SM_RPOOL_T *rpool;
384 {
385         SM_RLIST_T *rl, *rnext;
386         SM_RESOURCE_T *r, *rmax;
387         SM_POOLLINK_T *pp, *pnext;
388
389         if (rpool == NULL)
390                 return;
391
392         /*
393         **  It's important to free the resources before the memory pools,
394         **  because the resource free functions might modify the contents
395         **  of the memory pools.
396         */
397
398         rl = rpool->sm_rlists;
399         if (rl != NULL)
400         {
401                 rmax = rpool->sm_rptr;
402                 for (;;)
403                 {
404                         for (r = rl->sm_rvec; r < rmax; ++r)
405                         {
406                                 if (r->sm_rfree != NULL)
407                                         r->sm_rfree(r->sm_rcontext);
408                         }
409                         rnext = rl->sm_rnext;
410                         sm_free(rl);
411                         if (rnext == NULL)
412                                 break;
413                         rl = rnext;
414                         rmax = &rl->sm_rvec[SM_RLIST_MAX];
415                 }
416         }
417
418         /*
419         **  Now free the memory pools.
420         */
421
422         for (pp = rpool->sm_pools; pp != NULL; pp = pnext)
423         {
424                 pnext = pp->sm_pnext;
425                 sm_free(pp);
426         }
427
428         /*
429         **  Disconnect rpool from its parent.
430         */
431
432         if (rpool->sm_parentlink != NULL)
433                 *rpool->sm_parentlink = NULL;
434
435         /*
436         **  Setting these fields to zero means that any future to attempt
437         **  to use the rpool after it is freed will cause an assertion failure.
438         */
439
440         rpool->sm_magic = NULL;
441         rpool->sm_poolavail = 0;
442         rpool->sm_ravail = 0;
443
444 #if _FFR_PERF_RPOOL
445         if (rpool->sm_nbigblocks > 0 || rpool->sm_npools > 1)
446                 syslog(LOG_NOTICE,
447                         "perf: rpool=%lx, sm_nbigblocks=%d, sm_npools=%d",
448                         (long) rpool, rpool->sm_nbigblocks, rpool->sm_npools);
449         rpool->sm_nbigblocks = 0;
450         rpool->sm_npools = 0;
451 #endif /* _FFR_PERF_RPOOL */
452         sm_free(rpool);
453 }
454
455 /*
456 **  SM_RPOOL_ATTACH_X -- attach a resource to an rpool.
457 **
458 **      Parameters:
459 **              rpool -- rpool to which resource should be attached.
460 **              rfree -- function to call when rpool is freed.
461 **              rcontext -- argument for function to call when rpool is freed.
462 **
463 **      Returns:
464 **              Pointer to allocated function.
465 **
466 **      Exceptions:
467 **              F:sm_heap -- out of memory
468 */
469
470 SM_RPOOL_ATTACH_T
471 sm_rpool_attach_x(rpool, rfree, rcontext)
472         SM_RPOOL_T *rpool;
473         SM_RPOOL_RFREE_T rfree;
474         void *rcontext;
475 {
476         SM_RLIST_T *rl;
477         SM_RPOOL_ATTACH_T a;
478
479         SM_REQUIRE_ISA(rpool, SmRpoolMagic);
480
481         if (rpool->sm_ravail == 0)
482         {
483                 rl = sm_malloc_x(sizeof(SM_RLIST_T));
484                 rl->sm_rnext = rpool->sm_rlists;
485                 rpool->sm_rlists = rl;
486                 rpool->sm_rptr = rl->sm_rvec;
487                 rpool->sm_ravail = SM_RLIST_MAX;
488         }
489
490         a = &rpool->sm_rptr->sm_rfree;
491         rpool->sm_rptr->sm_rfree = rfree;
492         rpool->sm_rptr->sm_rcontext = rcontext;
493         ++rpool->sm_rptr;
494         --rpool->sm_ravail;
495         return a;
496 }
497
498 #if DO_NOT_USE_STRCPY
499 /*
500 **  SM_RPOOL_STRDUP_X -- Create a copy of a C string
501 **
502 **      Parameters:
503 **              rpool -- rpool to use.
504 **              s -- the string to copy.
505 **
506 **      Returns:
507 **              pointer to newly allocated string.
508 */
509
510 char *
511 sm_rpool_strdup_x(rpool, s)
512         SM_RPOOL_T *rpool;
513         const char *s;
514 {
515         size_t l;
516         char *n;
517
518         l = strlen(s);
519         SM_ASSERT(l + 1 > l);
520         n = sm_rpool_malloc_x(rpool, l + 1);
521         sm_strlcpy(n, s, l + 1);
522         return n;
523 }
524 #endif /* DO_NOT_USE_STRCPY */