chiark / gitweb /
@@@ pool upgrade
[mLib] / mem / pool.c
1 /* -*-c-*-
2  *
3  * Resource pool handling
4  *
5  * (c) 2000 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <string.h>
34
35 #ifdef HAVE_VALGRIND_VALGRIND_H
36 #  include <valgrind/valgrind.h>
37 #  include <valgrind/memcheck.h>
38 #  define VG(x) x
39 #else
40 #  define VG(x)
41 #endif
42
43 #include "align.h"
44 #include "alloc.h"
45 #include "arena.h"
46 #include "exc.h"
47 #include "macros.h"
48 #include "pool.h"
49
50 #ifdef DEBUG_POOL
51 #  include <stdio.h>
52 #  define D(x) x
53 #else
54 #  define D(x)
55 #endif
56
57 /*----- Pool memory layout ------------------------------------------------*
58  *
59  * The pool consists of a number of chunks.  Each chunk begins with a header,
60  * followed by allocated blocks.
61  *
62  * Within a chunk, blocks are allocated on alignment boundaries, as
63  * determined by the @ALIGN@ macro.  Furthermore, if Valgrind is active, then
64  * each allocation is preceded and followed by a guard area called a `red
65  * zone' which is @REDZONE_SIZE@ bytes in size.  For a block in the middle of
66  * the chunk, the leading red zone overlaps the previous block's trailing red
67  * zone, and the block's trailing red zone overlaps the following block's
68  * leading red zone.  If the block sizes are fully aligned, then the red
69  * zones completely coincide.
70  *
71  * An alternative view of the same situation, which produces the same
72  * allocation addresses, is that, following the chunk header and each
73  * allocated block, there is alignment padding followed by a red zone.  This
74  * view is helpful because it makes allocation uniform: to allocate a block,
75  * round up the requested size by aligning it at adding space for the
76  * following red zone; the current allocation pointer is the new block base
77  * address, and the allocation pointer is advanced by the rounded-up size.
78  *
79  * Three categories of chunks are maintained.
80  *
81  *   * There is always exactly one %%\emph{active}%% chunk.  This is the
82  *     chunk from which the most recent allocation, if any, was taken, and
83  *     the first chunk to be examined for the next allocation.
84  *
85  *   * There are zero or more %%\emph{live}%% chunks, which are not active
86  *     but still have space remaining for further allocations.  These are
87  *     maintained in a max-heap.
88  *
89  *     The live chunk with the greatest amount of free space is called the
90  *     `live head', and is the first element of the live heap vector.  The
91  *     idea here is that, in order to decide whether we can satisfy an
92  *     allocation from the pool's existing chunks, we need only check the
93  *     active chunk and the live head.
94  *
95  *   * There are zero or more %%\emph{dead}%% chunks, whose space has been
96  *     entirely allocated.  The dead chunks are held on a singly-linked list
97  *     which is only maintained so that the chunks can be recycled or
98  *     released.
99  *
100  *     Note that the active chunk is not considered dead even if an
101  *     allocation exhausts it: the invariant that the active chunk was the
102  *     source of the most recent allocation is more important, since this
103  *     allows us to free or reallocate the most recent allocation.
104  *
105  * A live or active chunk maintains an allocation pointer and remaining
106  * size.  In a dead chunk, the remaining size -- which is, by definition,
107  * zero, is replaced by the link to the next dead chunk in the list.
108  */
109
110 /*----- Constants ---------------------------------------------------------*/
111
112 #define REDZONE_SIZE (2*ALIGNOF(union align))
113 #define MIN_LIVESZ 16
114
115 /*----- Arena operations --------------------------------------------------*/
116
117 /* Here so that @pool_ops@ is available to @init_pool@ below. */
118
119 static void *palloc(arena *a, size_t sz)
120   { pool *p = (pool *)a; return (pool_alloc(p, sz)); }
121
122 static void *prealloc(arena *a, void *q, size_t newsz, size_t oldsz)
123   { pool *p = (pool *)a; return (pool_realloc(p, q, newsz, oldsz)); }
124
125 static void pfree(arena *a, void *q)
126   { pool *p = (pool *)a; pool_free(p, q); }
127
128 static arena_ops pool_ops = { palloc, prealloc, pfree, 0 };
129
130 /*----- Internal machinery ------------------------------------------------*/
131
132 /* --- @round_up@ --- *
133  *
134  * Arguments:   @size_t sz@ = an object size
135  *              @unsigned f@ = flags (@PF_...@)
136  *
137  * Returns:     The size to actually allocate, including alignment and a
138  *              possible following red zone.  (A %%\emph{preceding}%%
139  *              red zone doesn't concern us: it would  either be part of the
140  *              previous allocation or chunk header.)
141  */
142
143 static size_t round_up(size_t sz, unsigned f)
144 {
145   ALIGN(sz); VG( if (f&PF_VALGRIND) sz += REDZONE_SIZE; )
146   return (sz);
147 }
148
149 /* --- @chunk_bounds@ --- *
150  *
151  * Arguments:   @pool_chunk@ = the chunk
152  *              @size_t chsz@ = precomputed chunk header size, rounded up
153  *              @unsigned char **guard_out@ = where to put the guard address
154  *              @unsigned char **start_out@ = where to put the start address
155  *              @unsigned char **end_out@ = where to put the limit address
156  *
157  * Returns:     ---
158  *
159  * Use:         Determine and return the important boundary addresses
160  *              describing the allocatable space within the chunk, i.e., the
161  *              space following the header.
162  *
163  *              The guard address is the address of the first byte following
164  *              the chunk header, without any alignment.  The start address
165  *              is the base address of the first allocatable byte in the
166  *              chunk, immediately following the alignment and redzone after
167  *              the chunk header.  The end address is the address of the
168  *              first byte after the chunk.
169  *
170  *              The chunk's @u.sz@ member must be active -- if the chunk is
171  *              dead, then @u.sz@ should be zero.
172  */
173
174 static void chunk_bounds(pool_chunk *chunk, size_t chsz,
175                          unsigned char **guard_out,
176                          unsigned char **start_out, unsigned char **end_out)
177 {
178   *guard_out = (unsigned char *)(chunk + 1);
179   *start_out = (unsigned char *)chunk + chsz;
180   *end_out = chunk->p + chunk->u.sz;
181 }
182
183 /* --- @init_pool@ --- *
184  *
185  * Arguments:   @pool *p@ = pointer to storage for the control block
186  *              @arena *a@ = pointer to underlying arena
187  *              @pool_chunk *active@ = pointer to initial active chunk
188  *              @unsigned f@ = flags (@PF_...@)
189  *
190  * Returns:     ---
191  *
192  * Use:         Initializes a pool control block.  Valgrind is not informed.
193  *              This is a common subroutine for @pool_create@ and @pool_sub@.
194  */
195
196 static void init_pool(pool *p, arena *a, pool_chunk *active, unsigned f)
197 {
198   p->a.ops = &pool_ops;
199   p->active = active; p->resources = 0; p->pa = a; p->f = f; p->lastsz = 0;
200   p->live = 0; p->nlive = p->livesz = 0; p->dead = 0;
201 }
202
203 /* --- @alloc_chunk@ --- *
204  *
205  * Arguments:   @arena *a@ = arena to allocate from
206  *              @size_t minsz@ = size of the block intended to be allocated
207  *                      from this new chunk
208  *              @unsigned f@ = flags (@PF_...@)
209  *
210  * Returns:     A pointer to the new chunk.
211  *
212  * Use:         Subroutine to allocate a chunk.  Since a pool control block
213  *              is allocated out of its own storage, it's necessary to be
214  *              able to do this without reference to a pool.  Valgrind is not
215  *              informed.
216  *
217  *              This code is shared between @pool_create@, @pool_sub@, and
218  *              @internal_alloc@.
219  */
220
221 static pool_chunk *alloc_chunk(arena *a, size_t minsz, unsigned f)
222 {
223   pool_chunk *chunk;
224   size_t sz, chsz = round_up(sizeof(pool_chunk), f);
225
226   /* Allocate the chunk. */
227   sz = chsz + minsz + POOL_CHUNKSZ - 1; sz -= sz%POOL_CHUNKSZ;
228   chunk = x_alloc(a, sz);
229
230   /* Initialize and mark the body as unavailable. */
231   chunk->p = (unsigned char *)chunk + chsz; chunk->u.sz = sz - chsz;
232
233   /* Done. */
234   D( fprintf(stderr, ";; POOL new chunk %p + %lu\n",
235              (void *)chunk, (unsigned long)sz); )
236   return (chunk);
237 }
238
239 /* --- @report_new_chunk_to_valgrind@ --- *
240  *
241  * Arguments:   @pool *p@ = pointer to the pool
242  *              @pool_chunk *chunk@ = the new chunk to report
243  *
244  * Returns:     ---
245  *
246  * Use:         Inform Valgrind about the new chunk, which is surprisingly
247  *              involved.  This can't be done as part of allocating it
248  *              because we need to know the pool control-block address.
249  */
250
251 #ifdef HAVE_VALGRIND_VALGRIND_H
252
253 static void report_new_chunk_to_valgrind(pool *p, pool_chunk *chunk)
254 {
255   unsigned char *guard, *start, *end;
256
257   D( fprintf(stderr, ";; POOL prepare chunk %p\n", (void *)chunk); )
258
259   chunk_bounds(chunk, round_up(sizeof(pool_chunk), PF_VALGRIND),
260                &guard, &start, &end);
261
262   D( fprintf(stderr, ";; POOL \tchunk body %p + %lu\n",
263              (void *)start, (unsigned long)(end - start)); )
264   VALGRIND_MEMPOOL_ALLOC(p, start, end - start);
265
266   D( fprintf(stderr, ";; POOL \telectrify chunk %p + %lu\n",
267              (void *)guard, (unsigned long)(end - guard)); )
268   VALGRIND_MAKE_MEM_NOACCESS(guard, end - guard);
269 }
270
271 #endif
272
273 /* --- @maybe_undo_last_alloc@ --- *
274  *
275  * Arguments:   @pool *p@ = pointer to the pool
276  *              @void *q@ = pointer to an allocated block
277  *
278  * Returns:     Zero on success, %$-1$% if @q@ doesn't refer to the most
279  *              recent allocation.
280  *
281  * Use:         If @q@ points to the most recently allocated block, then
282  *              undo its allocation by adjusting the containing chunk's @p@
283  *              and @sz@ members.  The actual block contents are preserved,
284  *              and Valgrind is not informed.  If @q@ does not point to the
285  *              most recently allocated block, then return %$-1$% without
286  *              doing anything else.
287  */
288
289 static int maybe_undo_last_alloc(pool *p, void *q)
290 {
291   pool_chunk *chunk = p->active;
292   size_t sz = p->lastsz;
293
294   /* Check the base address.  If it's wrong then we fail. */
295   if (q != chunk->p - sz) return (-1);
296
297   /* Adjust the chunk so that the last allocation didn't happen. */
298   chunk->p -= sz; chunk->u.sz += sz;
299   return (0);
300 }
301
302 /* --- @bury_dead_chunk@ --- *
303  *
304  * Arguments:   @pool *p@ = pointer to the pool
305  *              @pool_chunk *chunk@ = the chunk to check
306  *
307  * Returns:     Zero if the chunk was dead and has now been buried, %$-1$% if
308  *                      it wasn't dead after all.
309  *
310  * Use:         If the chunk is dead -- it has insufficient space to satisfy
311  *              any reasonable request -- then link it onto the dead list and
312  *              return zero.
313  */
314
315 static int bury_dead_chunk(pool *p, pool_chunk *chunk)
316 {
317   size_t min = round_up(1, p->f);
318   size_t sz = chunk->u.sz;
319
320   /* If there's enough for the tiniest nonzero allocation then refuse to bury
321    * the chunk.
322    */
323   if (sz >= min) return (-1);
324
325   D( fprintf(stderr, ";; POOL move active chunk %p (%lu) to dead list\n",
326              (void *)chunk, (unsigned long)sz); )
327
328   /* Advance the allocation pointer to the end so that we can recycle the
329    * chunk later.
330    */
331   chunk->p += sz;
332
333   /* Link the chunk onto the dead list. */
334   chunk->u.next = p->dead; p->dead = chunk;
335
336   /* Done. */
337   return (0);
338 }
339
340 /* --- @upheap --- *
341  *
342  * Arguments:   @pool *p@ = pointer to the pool
343  *              @pool_chunk *new_chunk@ = a live chunk to be added
344  *
345  * Returns:     ---
346  *
347  * Use:         Append @new_chunk@ to the heap of live chunks.
348  *
349  *              This is the primitive function for fixing up the heap
350  *              underlying @remember_chunk@, but is also used by
351  *              @pool_recycle@.
352  */
353
354 static void upheap(pool *p, pool_chunk *new_chunk)
355 {
356   pool_chunk *chunk;
357   size_t i = p->nlive++, j,
358     chunksz, newsz = new_chunk->u.sz;
359
360   /* If there's not enough space in the vector for the new chunk then we must
361    * resize it.
362    */
363   if (i >= p->livesz) {
364     if (p->live) { X_RENEWV(p->live, p->pa, 2*i, i); p->livesz = 2*i; }
365     else { X_NEWV(p->live, p->pa, MIN_LIVESZ); p->livesz = MIN_LIVESZ; }
366   }
367
368   /* Work upwards through the live heap to find the right level for the new
369    * chunk.
370    */
371   while (i) {
372
373     /* Find the parent. */
374     j = (i - 1)/2; chunk = p->live[j]; chunksz = chunk->u.sz;
375
376     /* If the parent doesn't have less space than the new chunk then it's
377      * found its place.
378      */
379     if (chunksz >= newsz) break;
380
381     /* Demote the parent and ascend. */
382     p->live[i] = chunk; i = j;
383   }
384
385   /* We've found the right level. */
386   p->live[i] = new_chunk;
387 }
388
389 /* --- @retire_active_chunk@ --- *
390  *
391  * Arguments:   @pool *p@ = pointer to the pool
392  *              @pool_chunk *old_active@ = the old active chunk
393  *
394  * Returns:     ---
395  *
396  * Use:         The currently active chunk is about to be replaced.  Add the
397  *              old active chunk to the live heap or the dead list as
398  *              appropriate.
399  */
400
401 static void retire_active_chunk(pool *p, pool_chunk *old_active)
402 {
403   if (bury_dead_chunk(p, old_active)) {
404     D( fprintf(stderr, ";; POOL move active chunk %p (%lu) to live heap\n",
405                (void *)old_active, (unsigned long)old_active->u.sz); )
406     upheap(p, old_active);
407   }
408 }
409
410 /* --- @downheap@ --- *
411  *
412  * Arguments:   @pool *p@ = pointer to the pool
413  *              @pool_chunk *new_chunk@ = a new live chunk to be added to the
414  *                      heap to replace the previous head chunk
415  *
416  * Returns:     ---
417  *
418  * Use:         Replace the current live head with @new_chunk@ in the live
419  *              heap.
420  *
421  *              This is the primitive function for fixing up the heap
422  *              underlying @replace_live_head@.
423  */
424
425 static void downheap(pool *p, pool_chunk *new_chunk)
426 {
427   pool_chunk *chunk, *left, *right;
428   size_t i = 0, j, l, r, n = p->nlive,
429     leftsz, rightsz, chunksz, newsz = new_chunk->u.sz;
430
431   /* Start at the top and work downwards through the leap to find the right
432    * level for the new chunk.
433    */
434   for (;;) {
435
436     /* Find the two children. */
437     l = 2*i + 1; r = l + 1;
438
439     /* If the left child slot is out of bounds then we can descend no
440      * further.
441      */
442     if (l >= n) break;
443
444     if (r >= n) {
445       /* If the right child slot is out of bounds, then we must compare with
446        * the left only.
447        */
448
449       j = l; chunk = p->live[j]; chunksz = chunk->u.sz;
450     } else {
451       /* Otherwise we compare with the greater child.  If they're equal then
452        * choose the right in order to end the search slightly faster.
453        */
454
455       left = p->live[l]; leftsz = left->u.sz;
456       right = p->live[r]; rightsz = right->u.sz;
457       if (leftsz > rightsz) { j = l; chunk = left; chunksz = leftsz; }
458       else { j = r; chunk = right; chunksz = rightsz; }
459     }
460
461     /* If the new chunk is not less than the greater child then it's found
462      * its place.
463      */
464     if (newsz >= chunksz) break;
465
466     /* Promote the larger child and descend. */
467     p->live[i] = chunk; i = j;
468   }
469
470   /* We've found the right level. */
471   p->live[i] = new_chunk;
472 }
473
474 /* --- @replace_live_head@ --- *
475  *
476  * Arguments:   @pool *p@ = pointer to the pool
477  *              @pool_chunk *new_chunk@ = a new chunk to be added to the
478  *                      heap to replace the previous head chunk, or null
479  *
480  * Returns:     ---
481  *
482  * Use:         The old heap head -- the chunk with the largest free space --
483  *              has been removed from the heap to be reactivated, and is to
484  *              be replaced by @new_chunk@ -- or by nothing, if @new_chunk@
485  *              is null.  If the  @new_chunk@ is completely exhausted, then
486  *              instead link it onto the @p->dead@ list and shrink the heap.
487  */
488
489 static void replace_live_head(pool *p, pool_chunk *new_chunk)
490 {
491   size_t n;
492
493   /* If there's a new chunk, and it still has some space left, then we can
494    * proceed.  If it's exhausted, then put it on the dead list.
495    */
496   if (new_chunk) {
497     if (bury_dead_chunk(p, new_chunk)) {
498       D( fprintf(stderr, ";; POOL move active chunk %p (%lu) to live heap\n",
499                  (void *)new_chunk, (unsigned long)new_chunk->u.sz); )
500       downheap(p, new_chunk); return;
501     }
502   }
503
504   /* If there are no other chunks in the heap, then it will be left empty;
505    * otherwise, we replace the head with the chunk with the highest index.
506    */
507   n = --p->nlive;
508   if (n) downheap(p, p->live[n]);
509
510 }
511
512 /* --- @internal_alloc@ --- *
513  *
514  * Arguments:   @pool *p@ = pointer to the pool
515  *              @size_t sz@ = size required
516  *
517  * Returns:     A pointer to the newly allocated block.
518  *
519  * Use:         Allocate and return a block from the pool.  No data in any
520  *              chunk is modified; Valgrind is not informed.  This is a
521  *              common subroutine of @pool_alloc@ and @pool_realloc@.
522  */
523
524 static void *internal_alloc(pool *p, size_t sz)
525 {
526   pool_chunk *active, *head;
527   void *q;
528   size_t n;
529
530   /* Align the size and add on the trailing red zone.  The leading red zone
531    * follows the previous allocation or the chunk header.
532    */
533   sz = round_up(sz, p->f);
534
535   /* Try to serve the request from the active chunk. */
536   active = p->active;
537   if (active->u.sz >= sz) goto alloc;
538
539   /* Explore the heap of live chunks. */
540   n = p->nlive;
541   if (n) {
542     /* There's at least one chunk in the heap.  Maybe that will help. */
543
544     head = p->live[0];
545
546     /* If the topmost chunk in the heap is large enough, then we'll activate
547      * that one.
548      */
549     if (head->u.sz >= sz) {
550
551       /* We'll take the old heap head chunk, and replace it with the
552        * previously active chunk (or put it on the dead list and shrink).
553        */
554       replace_live_head(p, active);
555
556       /* Allocate from the previous head chunk. */
557       D( fprintf(stderr, ";; POOL activate old live head %p\n",
558                  (void *)head); )
559       p->active = active = head;
560       goto alloc;
561     }
562   }
563
564   /* There are no other suitable chunks.  Just put the old active chunk on
565    * the heap (or the dead list).
566    */
567   retire_active_chunk(p, active);
568
569   /* There's not enough space in any chunk.  Add the old active chunk to
570    * the heap and allocate a fresh one.
571    */
572   p->active = active = alloc_chunk(p->pa, sz, p->f);
573   VG( if (p->f&PF_VALGRIND) report_new_chunk_to_valgrind(p, active); )
574
575 alloc:
576   /* Allocate the new block.  Save the (aligned, padded) size for use by
577    * @maybe_undo_last_alloc@.
578    */
579   q = active->p; active->p += sz; active->u.sz -= sz;
580   p->lastsz = sz;
581
582   /* All done. */
583   return (q);
584 }
585
586 /* --- @release_resources@ --- *
587  *
588  * Arguments:   @pool *p@ = pointer to the pool
589  *
590  * Returns:     ---
591  *
592  * Use:         Release all of the resources tracked by the pool.  The
593  *              resource list is %%\emph{not}%% cleared -- there'd be no
594  *              point if the pool as a whole is about to be destroyed.
595  */
596
597 static void release_resources(pool *p)
598 {
599   pool_resource *r, *rr;
600
601   for (r = p->resources; r; r = rr)
602     { rr = r->next; if (r->destroy) r->destroy(r); }
603 }
604
605 /* --- @recycle_chunk@ --- *
606  *
607  * Arguments:   @pool *p@ = pointer to the pool
608  *              @pool_chunk *chunk@ = the chunk to be cleared
609  *              @size_t chsz@ = precomputed chunk header size, rounded up
610  *
611  * Returns:     ---
612  *
613  * Use:         Clear a single chunk: reset the allocation pointer and size
614  *              to refer to the entire chunk, and inform Valgrind that the
615  *              old allocations from the chunk are now invalid.  As a special
616  *              case, if this chunk is the one that contains the pool control
617  *              block, then reallocate space for the control block.
618  *
619  *              The chunk must be in its `live' form, with the @sz@ member
620  *              active.
621  */
622
623 static void recycle_chunk(pool *p, pool_chunk *chunk, size_t chsz)
624 {
625   unsigned f = p->f;
626   unsigned char *guard, *start, *end;
627   size_t psz;
628
629   /* Reset the chunk bounds. */
630   chunk_bounds(chunk, chsz, &guard, &start, &end);
631   chunk->p = start; chunk->u.sz = end - start;
632
633   /* Clear Valgrind's ideas about the chunk. */
634   VG( if (f&PF_VALGRIND) {
635
636         D( fprintf(stderr, ";; POOL recycle chunk %p\n", (void *)chunk); )
637         D( fprintf(stderr, ";; POOL \trecycle body %p + %zu\n",
638                    (void *)start, (unsigned long)(end - start)); )
639         VALGRIND_MEMPOOL_FREE(p, start);
640         VALGRIND_MEMPOOL_ALLOC(p, start, end - start);
641
642         D( fprintf(stderr, ";; POOL \telectrify body %p + %zu\n",
643                    (void *)guard, (unsigned long)(guard - start)); )
644         VALGRIND_MAKE_MEM_NOACCESS(guard, end - guard);
645       } )
646
647   /* Check to see if this is the chunk which contains the pool control
648    * block.  If so, we need to advance the allocation pointer beyond the
649    * control block.  Be sure to tell Valgrind that the control block has
650    * known contents.
651    */
652   if (start == (unsigned char *)p) {
653     psz = round_up(sizeof(pool), f);
654     chunk->p += psz; chunk->u.sz -= psz;
655     VG( if (f&PF_VALGRIND)
656           VALGRIND_MALLOCLIKE_BLOCK(p, sizeof(p), REDZONE_SIZE, 1); )
657   }
658 }
659
660 /* --- @free_chunk@ --- *
661  *
662  * Arguments:   @pool *p@ = pointer to the pool (only used for Valgrind)
663  *              @arena *a@ = pointer to underlying arena
664  *              @pool_chunk *chunk@ = the chunk to be freed
665  *              @unsigned f@ = flags (@PF_...@)
666  *              @size_t chsz@ = precomputed chunk header size, rounded up
667  *
668  * Returns:     ---
669  *
670  * Use: Free the chunk, handling the Valgrind necessities.  The pool control
671  *              block isn't necessarily valid so all of the pieces need to be
672  *              passed separately.
673  */
674
675 static void free_chunk(pool *p, arena *a,
676                        pool_chunk *chunk, unsigned f, size_t chsz)
677 {
678   VG( unsigned char *guard COMMA *start COMMA *end; )
679
680   VG( if (f&PF_VALGRIND) {
681         chunk_bounds(chunk, chsz, &guard, &start, &end);
682         D( fprintf(stderr, ";; POOL free chunk %p\n", (void *)chunk);
683            fprintf(stderr, ";; POOL \tclear body %p\n", (void *)start); )
684         VALGRIND_MEMPOOL_FREE(p, start);
685       } )
686
687   A_FREE(a, chunk);
688 }
689
690 /* --- @free_chunks@ --- *
691  *
692  * Arguments:   @pool *p@ = pointer to the pool
693  *              @unsigned f@ = flags (@FF_...@)
694  *
695  * Returns:     ---
696  *
697  * Use:         Free all of the pool's live and dead chunks, returning them
698  *              to the underlying arena.
699  *
700  *              If @FF_ACTIVE@ is set in @f@, then also free the active
701  *              chunk.  If @FF_LIVE@ is set, then also free the live heap
702  *              vector.  (The live chunks are always freed; the flag
703  *              additionally frees the underlying vector.)
704  *
705  *              If the pool is a root pool, then may no longer be valid; this
706  *              is a certainty if @FF_ACTIVE@ is set.
707  */
708
709 #define FF_ACTIVE 1u
710 #define FF_LIVE 2u
711
712 static void free_chunks(pool *p, unsigned f)
713 {
714   pool_chunk *chunk, *next_chunk,
715     *active = p->active, **live = p->live, *dead = p->dead;
716   unsigned pf = p->f;
717   size_t i, nlive = p->nlive, chsz = round_up(sizeof(pool_chunk), pf);
718   arena *a = p->pa;
719
720   /* Maybe free the active chunk. */
721   if (f&FF_ACTIVE)
722     free_chunk(p, a, active, pf, chsz);
723
724   /* Free the live chunks. */
725   for (i = 0; i < nlive; i++)
726     free_chunk(p, a, live[i], pf, chsz);
727   if (live && (f&FF_LIVE)) A_FREE(a, live);
728
729   /* Free the dead chunks. */
730   for (chunk = dead; chunk; chunk = next_chunk) {
731     next_chunk = chunk->u.next;
732     free_chunk(p, a, chunk, pf, chsz);
733   }
734 }
735
736 /* --- @internal_destroy@ --- *
737  *
738  * Arguments:   @pool *p@ = pointer to pool to destroy
739  *
740  * Returns:     ---
741  *
742  * Use:         Destroy a pool, freeing all of the resources and memory held
743  *              by it, with the certainty that it will never be used again --
744  *              either this is a root pool, or it's a subpool being torn down
745  *              by its parent.
746  */
747
748 static void internal_destroy(pool *p)
749   { release_resources(p); free_chunks(p, FF_ACTIVE | FF_LIVE); }
750
751 /*----- Main operations ---------------------------------------------------*/
752
753 /* --- @pool_create@ --- *
754  *
755  * Arguments:   @arena *a@ = pointer to an arena to allocate memory from
756  *
757  * Returns:     A newly created resource pool.
758  *
759  * Use:         Creates a fresh root resource pool, i.e., one  which is not a
760  *              child of any other pool.
761  */
762
763 pool *pool_create(arena *a)
764 {
765   pool_chunk *active;
766   pool *p;
767   size_t psz;
768   unsigned f = 0;
769
770   /* Setup. */
771   VG( if (RUNNING_ON_VALGRIND) f |= PF_VALGRIND; )
772
773   /* Allocate the initial chunk. */
774   psz = round_up(sizeof(pool), f);
775   active = alloc_chunk(a, psz, f);
776
777   /* Allocate the pool control block from the chunk. */
778   p = (pool *)active->p; active->p += psz; active->u.sz -= psz;
779
780   /* Tell Valgrind about the pool. */
781   VG( if (f&PF_VALGRIND) {
782         VALGRIND_CREATE_MEMPOOL_EXT(p, REDZONE_SIZE, 0,
783                                     VALGRIND_MEMPOOL_METAPOOL |
784                                     VALGRIND_MEMPOOL_AUTO_FREE);
785         report_new_chunk_to_valgrind(p, active);
786         VALGRIND_MALLOCLIKE_BLOCK(p, sizeof(pool), REDZONE_SIZE, 0);
787       } )
788
789   /* Initialize the control block. */
790   init_pool(p, a, active, f);
791
792   /* Done. */
793   return (p);
794 }
795
796 /* --- @pool_alloc@, @pool_allocv@ --- *
797  *
798  * Arguments:   @pool *p@ = pool to allocate from
799  *              @size_t n@ = number of elements to allocate (for
800  *                      @pool_allocv@)
801  *              @size_t sz@ = size of block wanted
802  *
803  * Returns:     Pointer to the requested block.
804  *
805  * Use:         The @pool_allocv@ function allocates memory for @n@ elements
806  *              of @sz@ bytes each from a resource pool.  Only the most
807  *              recent allocation can usefully be adjusted and/or freed;
808  *              other allocations persist until the pool is destroyed.  The
809  *              @pool_alloc@ function is the same, but with @n@ fixed equal
810  *              to 1.  If there's not enough memory, the exception
811  *              @EXC_NOMEM@ is thrown.
812  */
813
814 void *pool_alloc(pool *p, size_t sz)
815 {
816   void *q = internal_alloc(p, sz);
817
818   VG( if (p->f&PF_VALGRIND)
819         VALGRIND_MALLOCLIKE_BLOCK(q, sz, REDZONE_SIZE, 0); )
820   return (q);
821 }
822
823 void *pool_allocv(pool *p, size_t n, size_t sz)
824 {
825   if (!ALLOCV_SAFE_P(n, sz)) THROW(EXC_NOMEM);
826   else return (pool_alloc(p, n*sz));
827 }
828
829 /* --- @pool_realloc@, @pool_reallocv@ --- *
830  *
831  * Arguments:   @pool *p@ = pointer to the pool
832  *              @void *q@ = pointer to block
833  *              @size_t n@ = new number of elements (for @pool_reallocv@)
834  *              @size_t on@ = old number of elements (for @pool_reallocv@)
835  *              @size_t sz@ = size of elements (for @pool_reallocv@)
836  *              @size_t newsz@ = the new size required (for @pool_realloc@)
837  *              @size_t oldsz@ = existing size allocated (for @pool_realloc@)
838  *
839  * Returns:     The new address of the block.
840  *
841  * Use:         The @pool_reallocv@ function returns a pointer to a block of
842  *              memory, large enough for @n@ elements each of size @sz@,
843  *              containing a copy of the first @min(n, on)@ elements
844  *              currently in the block at @q@.  If the new pointer is not
845  *              equal to @q@, then @q@ is invalidated and it is an error to
846  *              make further use of it.
847  *
848  *              If @q@ points to the most recently allocated block, then the
849  *              old storage is reclaimed.  Otherwise, if @n@ is smaller than
850  *              @on@, the block is shrunk in place, but the excess space is
851  *              lost until the pool is destroyed.  Otherwise, a fresh block
852  *              is allocated and the data copied, and the old block's space
853  *              is lost until the pool is destroyed.
854  *
855  *              The @pool_realloc@ function is the same, except that @sz@ is
856  *              fixed at 1, and @n@ and @on@ are renamed to @newsz@ and
857  *              @oldsz@.
858  */
859
860 void *pool_realloc(pool *p, void *q, size_t newsz, size_t oldsz)
861 {
862   void *qq;
863
864   /* The usual C special cases. */
865   if (!q) return (pool_alloc(p, newsz));
866   else if (!newsz) { pool_free(p, q); return (0); }
867
868   if (!maybe_undo_last_alloc(p, q)) {
869     /* The block being reallocated is the most recently allocated one, and
870      * its allocation has just been undone.  We'll retry the allocation.
871      * This will either return the same address again, if there is enough
872      * space in the chunk to satisfy the allocation, or a different address.
873      * In the former case, the existing data is still there and we have
874      * nothing to do (except update Valgrind's ideas about the block);
875      * otherwise, we must copy the data -- but note that, in this case, we
876      * know that the block must be growing.
877      */
878
879     qq = internal_alloc(p, newsz);
880     if (qq != q) {
881       VG( if (p->f&PF_VALGRIND)
882             VALGRIND_MALLOCLIKE_BLOCK(qq, newsz, REDZONE_SIZE, 0); )
883       memcpy(qq, q, oldsz);
884       VG( if (p->f&PF_VALGRIND) VALGRIND_FREELIKE_BLOCK(q, REDZONE_SIZE); )
885     }
886     VG( else if (p->f&PF_VALGRIND)
887           VALGRIND_RESIZEINPLACE_BLOCK(q, oldsz, newsz, REDZONE_SIZE); )
888
889   } else if (newsz < oldsz || (newsz ^ oldsz) < sizeof(union align)) {
890     /* The caller asked us to shrink the block.  There's nothing to do here
891      * except update Valgrind's idea about the allocation.
892      */
893
894     qq = q;
895     VG( if (p->f&PF_VALGRIND)
896           VALGRIND_RESIZEINPLACE_BLOCK(q, oldsz, newsz, REDZONE_SIZE); )
897
898   } else {
899     /* We've been asked to grow a block.  Just allocate a fresh one and copy
900      * the data.
901      */
902
903     qq = internal_alloc(p, newsz);
904     VG( if (p->f&PF_VALGRIND)
905           VALGRIND_MALLOCLIKE_BLOCK(qq, newsz, REDZONE_SIZE, 0); )
906     memcpy(qq, q, oldsz);
907     VG( if (p->f&PF_VALGRIND) VALGRIND_FREELIKE_BLOCK(q, REDZONE_SIZE); )
908   }
909
910   /* Return the new pointer. */
911   return (qq);
912 }
913
914 void *pool_reallocv(pool *p, void *q, size_t n, size_t on, size_t sz)
915 {
916   if (!ALLOCV_SAFE_P(n, sz)) THROW(EXC_NOMEM);
917   else return (pool_realloc(p, q, n*sz, on*sz));
918 }
919
920 /* --- @pool_strdup@ --- *
921  *
922  * Arguments:   @pool *p@ = pool to allocate from
923  *              @const char *s@ = pointer to string
924  *
925  * Returns:     A pointer to a copy of the string.
926  *
927  * Use:         Allocates a copy of a string.
928  */
929
930 char *pool_strdup(pool *p, const char *s)
931 {
932   size_t sz = strlen(s) + 1;
933   char *q;
934
935   q = internal_alloc(p, sz);
936   VG( if (p->f&PF_VALGRIND)
937         VALGRIND_MALLOCLIKE_BLOCK(q, sz, REDZONE_SIZE, 0); )
938   memcpy(q, s, sz);
939   return (q);
940 }
941
942 /* --- @pool_free@ --- *
943  *
944  * Arguments:   @pool *p@ = pointer to the pool
945  *              @void *q@ = pointer to block
946  *
947  * Returns:     ---
948  *
949  * Use:         Try to recycle the memory used by the block allocated at @q@.
950  *              If @q@ points to the most recently allocated block, then it
951  *              can be reclaimed at no cost.  Otherwise, the allocation
952  *              persists anyway until the pool as a whole is destroyed --
953  *              though the pointer is logically invalidated, and it is an
954  *              error to make further use of it.
955  */
956
957 void pool_free(pool *p, void *q)
958 {
959   /* Check if this was the most recent block.  If so, we can actually
960    * reclaim its space.
961    */
962   if (!maybe_undo_last_alloc(p, q)) {
963
964     /* If we're /not/ running under Valgrind then zero is a properly aligned
965      * length.  If we /are/, then this is the precise length of a free block.
966      */
967     p->lastsz = 0;
968
969     /* If we're running under Valgrind, then we should still leave a
970      * trailing red zone for two reasons: firstly, this will help detect
971      * accesses to the free block after a new real block is allocated; and
972      * secondly, this arrangement correctly preserves the last-block
973      * base-address invariant.
974      */
975     VG( if (p->f&PF_VALGRIND) {
976           p->active->p += REDZONE_SIZE;
977           p->active->u.sz -= REDZONE_SIZE;
978         } )
979   }
980
981   /* Tell Valgrind that the block is free. */
982   VG( if (p->f&PF_VALGRIND) VALGRIND_FREELIKE_BLOCK(q, REDZONE_SIZE); )
983 }
984
985 /* --- @pool_add@ --- *
986  *
987  * Arguments:   @pool *p@ = pointer to pool to add the resource to
988  *              @pool_resource *r@ = pointer to resource block
989  *              @void (*dfn)(pool_resource *r)@ = destruction function
990  *
991  * Returns:     ---
992  *
993  * Use:         Adds a resource to a pool.
994  */
995
996 void pool_add(pool *p, pool_resource *r, void (*dfn)(pool_resource *r))
997   { POOL_ADD(p, r, dfn); }
998
999 /* --- @pool_recycle@ --- *
1000  *
1001  * Arguments:   @pool *p@ = pointer to the pool
1002  *
1003  * Returns:     ---
1004  *
1005  * Use:         Release all of the memory and resources held by the pool,
1006  *              with the expectation that it will be used again.  The chunks
1007  *              from which allocations were satisfied are retained for future
1008  *              use.
1009  */
1010
1011 void pool_recycle(pool *p)
1012 {
1013   pool_chunk *chunk, *next_chunk;
1014   size_t i, n, chsz = round_up(sizeof(pool_chunk), p->f);
1015
1016   /* Release the pool's resources. */
1017   release_resources(p); p->resources = 0;
1018
1019   /* Deal with the heap first; otherwise, we'd have to make a copy of the
1020    * live chunks.
1021    */
1022   n = p->nlive;
1023   if (n) {
1024     p->nlive = 0;
1025     for (i = 0; i < n; i++) {
1026       chunk = p->live[i];
1027       recycle_chunk(p, chunk, chsz); upheap(p, chunk);
1028     }
1029   }
1030
1031   /* Throw in the current active chunk. */
1032   chunk = p->active;
1033   recycle_chunk(p, chunk, chsz); upheap(p, chunk);
1034
1035   /* And finally walk the dead list. */
1036   for (chunk = p->dead; chunk; chunk = next_chunk) {
1037     next_chunk = chunk->u.next; chunk->u.sz = 0;
1038     recycle_chunk(p, chunk, chsz); upheap(p, chunk);
1039   }
1040   p->dead = 0;
1041
1042   /* Activate the largest chunk. */
1043   p->active = p->live[0]; replace_live_head(p, 0); p->lastsz = 0;
1044 }
1045
1046 /* --- @pool_destroy@ --- *
1047  *
1048  * Arguments:   @pool *p@ = pointer to pool to destroy
1049  *
1050  * Returns:     ---
1051  *
1052  * Use:         Destroys a pool, freeing all of the resources within it.  If
1053  *              this is a root pool, its memory will be deallocated; if it's
1054  *              a subpool, it is emptied and can be used again.
1055  */
1056
1057 void pool_destroy(pool *p)
1058 {
1059   if (!(p->f&PF_SUBPOOL)) {
1060     /* This is a root pool, so just free all of the chunks and the live heap
1061      * vector.  The pool control block was allocated from one of these.
1062      */
1063
1064     internal_destroy(p);
1065   } else {
1066     /* This is a subpool, and the storage for its control block came from its
1067      * parent.  In principle, the pool could be used again; certainly, it
1068      * must be left safe for the parent to destroy it later.
1069      */
1070
1071     release_resources(p); p->resources = 0;
1072     recycle_chunk(p, p->active, round_up(sizeof(pool_chunk), p->f));
1073     free_chunks(p, 0); p->nlive = 0; p->dead = 0; p->lastsz = 0;
1074   }
1075 }
1076
1077 /*----- Subpools ----------------------------------------------------------*/
1078
1079 /* --- @pool_sub@ --- *
1080  *
1081  * Arguments:   @pool *p@ = pointer to parent pool
1082  *
1083  * Returns:     A new child pool of the parent.
1084  *
1085  * Use:         Creates a subpool.  The subpool can either be destroyed on
1086  *              its own, or will be automatically destroyed at the same time
1087  *              as the parent.
1088  */
1089
1090 typedef struct subpool {
1091   pool_resource r;
1092   pool p;
1093 } subpool;
1094
1095 static void subpool_destroy(pool_resource *r)
1096   { subpool *p = (subpool *)r; internal_destroy(&p->p); }
1097
1098 pool *pool_sub(pool *p)
1099 {
1100   subpool *pp = pool_alloc(p, sizeof(subpool));
1101   pool_chunk *active;
1102   arena *a = p->pa;
1103   unsigned f = p->f | PF_SUBPOOL;
1104
1105   /* Allocate the initial active chunk. */
1106   active = alloc_chunk(a, 1, f);
1107
1108   /* Set up the pool control block. */
1109   init_pool(&pp->p, a, active, f);
1110
1111   /* Tell Valgrind about the pool. */
1112   VG( if (p->f&PF_VALGRIND) {
1113         VALGRIND_CREATE_MEMPOOL_EXT(&pp->p, REDZONE_SIZE, 0,
1114                                     VALGRIND_MEMPOOL_METAPOOL |
1115                                     VALGRIND_MEMPOOL_AUTO_FREE);
1116         report_new_chunk_to_valgrind(&pp->p, active);
1117       } )
1118
1119   /* Register the subpool as a resource of its parent. */
1120   POOL_ADD(p, &pp->r, subpool_destroy);
1121
1122   /* And we're done. */
1123   return (&pp->p);
1124 }
1125
1126 /*----- That's all, folks -------------------------------------------------*/