1 /* PSPP - computes sample statistics.
2 Copyright (C) 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 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
29 /* Fast, low-overhead memory block suballocator. */
32 struct pool *parent; /* Pool of which this pool is a subpool. */
33 struct pool_block *blocks; /* Blocks owned by the pool. */
34 struct pool_gizmo *gizmos; /* Other stuff owned by the pool. */
40 struct pool_block *prev;
41 struct pool_block *next;
51 POOL_GIZMO_REGISTERED,
54 /* Pool routines can maintain objects (`gizmos') as well as doing
56 This structure is used to keep track of them. */
59 struct pool_gizmo *prev;
60 struct pool_gizmo *next;
62 long serial; /* Serial number. */
63 int type; /* Type of this gizmo. */
65 /* Type-dependent info. */
68 FILE *file; /* POOL_GIZMO_FILE. */
69 struct pool *subpool; /* POOL_GIZMO_SUBPOOL. */
71 /* POOL_GIZMO_REGISTERED. */
74 void (*free) (void *p);
82 /* Rounds X up to the next multiple of Y. */
84 #define ROUND_UP(X, Y) \
85 (((X) + ((Y) - 1)) / (Y) * (Y))
88 /* Types that provide typically useful alignment sizes. */
97 /* This should be the alignment size used by malloc(). The size of
98 the union above is correct, if not optimal, in all known cases. */
99 #if defined (i386) || defined (__i386__)
100 #define ALIGN_SIZE 4 /* Save some extra memory. */
102 #define ALIGN_SIZE sizeof (union align)
105 /* DISCRETE_BLOCKS may be declared as nonzero to prevent
106 suballocation of blocks. This is useful under memory
107 debuggers like Checker or valgrind because it allows the
108 source location of bugs to be more accurately pinpointed.
110 On the other hand, if we're testing the library, then we want to
111 test the library's real functionality, not its crippled, slow,
112 simplified functionality. */
113 /*#define DISCRETE_BLOCKS 1*/
115 /* Enable debug code if appropriate. */
119 /* Size of each block allocated in the pool, in bytes.
120 Should be at least 1k. */
122 #define BLOCK_SIZE 1024
125 /* Maximum size of a suballocated block. Larger blocks are allocated
126 directly with malloc() to avoid memory wastage at the end of a
127 suballocation block. */
129 #define MAX_SUBALLOC 64
132 /* Sizes of some structures with alignment padding included. */
133 #define POOL_BLOCK_SIZE ROUND_UP (sizeof (struct pool_block), ALIGN_SIZE)
134 #define POOL_GIZMO_SIZE ROUND_UP (sizeof (struct pool_gizmo), ALIGN_SIZE)
135 #define POOL_SIZE ROUND_UP (sizeof (struct pool), ALIGN_SIZE)
137 /* Serial number used to keep track of gizmos for mark/release. */
138 static long serial = 0;
141 static void add_gizmo (struct pool *, struct pool_gizmo *);
142 static void free_gizmo (struct pool_gizmo *);
143 static void free_all_gizmos (struct pool *pool);
144 static void delete_gizmo (struct pool *, struct pool_gizmo *);
147 static void *xmalloc (size_t);
148 static void *xrealloc (void *, size_t);
151 /* General routines. */
153 /* Creates and returns a new memory pool, which allows malloc()'d
154 blocks to be suballocated in a time- and space-efficient manner.
155 The entire contents of the memory pool are freed at once.
157 In addition, other objects can be associated with a memory pool.
158 These are released when the pool is destroyed. */
162 struct pool_block *block;
165 block = xmalloc (BLOCK_SIZE);
166 block->prev = block->next = block;
167 block->ofs = POOL_BLOCK_SIZE + POOL_SIZE;
169 pool = (struct pool *) (((char *) block) + POOL_BLOCK_SIZE);
171 pool->blocks = block;
177 /* Destroy the specified pool, including all subpools. */
179 pool_destroy (struct pool *pool)
184 /* Remove this pool from its parent's list of gizmos. */
186 delete_gizmo (pool->parent,
187 (void *) (((char *) pool) + POOL_SIZE + POOL_BLOCK_SIZE));
189 free_all_gizmos (pool);
191 /* Free all the memory. */
193 struct pool_block *cur, *next;
195 pool->blocks->prev->next = NULL;
196 for (cur = pool->blocks; cur; cur = next)
204 /* Release all the memory and gizmos in POOL.
205 Blocks are not given back with free() but kept for later
206 allocations. To give back memory, use a subpool instead. */
208 pool_clear (struct pool *pool)
210 free_all_gizmos (pool);
212 /* Zero out block sizes. */
214 struct pool_block *cur;
219 cur->ofs = POOL_BLOCK_SIZE;
220 if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
221 cur->ofs += POOL_SIZE;
224 while (cur != pool->blocks);
228 /* Suballocation routines. */
230 /* Allocates a memory region AMT bytes in size from POOL and returns a
231 pointer to the region's start. */
233 pool_alloc (struct pool *pool, size_t amt)
235 assert (pool != NULL);
237 #ifndef DISCRETE_BLOCKS
238 if (amt <= MAX_SUBALLOC)
240 /* If there is space in this block, take it. */
241 struct pool_block *b = pool->blocks;
242 b->ofs = ROUND_UP (b->ofs, ALIGN_SIZE);
243 if (b->ofs + amt <= BLOCK_SIZE)
245 void *const p = ((char *) b) + b->ofs;
250 /* No space in this block, so we must make other
252 if (b->next->ofs == 0)
254 /* The next block is empty. Use it. */
256 b->ofs = POOL_BLOCK_SIZE;
257 if ((char *) b + POOL_BLOCK_SIZE == (char *) pool)
262 /* Create a new block at the start of the list. */
263 b = xmalloc (BLOCK_SIZE);
264 b->next = pool->blocks;
265 b->prev = pool->blocks->prev;
266 b->ofs = POOL_BLOCK_SIZE;
267 pool->blocks->prev->next = b;
268 pool->blocks->prev = b;
272 /* Allocate space from B. */
274 return ((char *) b) + b->ofs - amt;
278 return pool_malloc (pool, amt);
281 /* Duplicates STRING, which has LENGTH characters, within POOL,
282 and returns a pointer to the duplicate. LENGTH should not
283 include the null terminator, which is always added to the
284 duplicate. For use only with strings, because the returned
285 pointere may not be aligned properly for other types. */
287 pool_strndup (struct pool *pool, const char *string, size_t length)
292 assert (pool && string);
295 /* Note that strings need not be aligned on any boundary. */
296 #ifndef DISCRETE_BLOCKS
298 struct pool_block *const b = pool->blocks;
300 if (b->ofs + size <= BLOCK_SIZE)
302 copy = ((char *) b) + b->ofs;
306 copy = pool_alloc (pool, size);
309 copy = pool_alloc (pool, size);
312 memcpy (copy, string, length);
317 /* Duplicates null-terminated STRING, within POOL, and returns a
318 pointer to the duplicate. For use only with strings, because
319 the returned pointere may not be aligned properly for other
322 pool_strdup (struct pool *pool, const char *string)
324 return pool_strndup (pool, string, strlen (string));
327 /* Standard allocation routines. */
329 /* Allocates AMT bytes using malloc(), to be managed by POOL, and
330 returns a pointer to the beginning of the block.
331 If POOL is a null pointer, then allocates a normal memory block
334 pool_malloc (struct pool *pool, size_t amt)
340 struct pool_gizmo *g = xmalloc (amt + POOL_GIZMO_SIZE);
341 g->type = POOL_GIZMO_MALLOC;
344 return ((char *) g) + POOL_GIZMO_SIZE;
350 return xmalloc (amt);
353 /* Changes the allocation size of the specified memory block P managed
354 by POOL to AMT bytes and returns a pointer to the beginning of the
356 If POOL is a null pointer, then the block is reallocated in the
357 usual way with realloc(). */
359 pool_realloc (struct pool *pool, void *p, size_t amt)
367 struct pool_gizmo *g;
369 g = xrealloc (((char *) p) - POOL_GIZMO_SIZE,
370 amt + POOL_GIZMO_SIZE);
378 return ((char *) g) + POOL_GIZMO_SIZE;
387 return pool_malloc (pool, amt);
390 return xrealloc (p, amt);
393 /* Frees block P managed by POOL.
394 If POOL is a null pointer, then the block is freed as usual with
397 pool_free (struct pool *pool, void *p)
399 if (pool != NULL && p != NULL)
401 struct pool_gizmo *g = (void *) (((char *) p) - POOL_GIZMO_SIZE);
402 delete_gizmo (pool, g);
409 /* Gizmo allocations. */
411 /* Creates and returns a pool as a subpool of POOL.
412 The subpool will be destroyed automatically when POOL is destroyed.
413 It may also be destroyed explicitly in advance. */
415 pool_create_subpool (struct pool *pool)
417 struct pool *subpool;
418 struct pool_gizmo *g;
420 assert (pool != NULL);
421 subpool = pool_create ();
422 subpool->parent = pool;
424 g = (void *) (((char *) subpool) + subpool->blocks->ofs);
425 subpool->blocks->ofs += POOL_GIZMO_SIZE;
427 g->type = POOL_GIZMO_SUBPOOL;
428 g->p.subpool = subpool;
435 /* Opens file FILENAME with mode MODE and returns a handle to it
436 if successful or a null pointer if not.
437 The file will be closed automatically when POOL is destroyed, or it
438 may be closed explicitly in advance using pool_fclose. */
440 pool_fopen (struct pool *pool, const char *filename, const char *mode)
444 assert (pool && filename && mode);
445 f = fopen (filename, mode);
450 struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
451 g->type = POOL_GIZMO_FILE;
459 /* Closes file FILE managed by POOL. */
461 pool_fclose (struct pool *pool, FILE *file)
463 assert (pool && file);
464 if (fclose (file) == EOF)
468 struct pool_gizmo *g;
470 for (g = pool->gizmos; g; g = g->next)
471 if (g->type == POOL_GIZMO_FILE && g->p.file == file)
473 delete_gizmo (pool, g);
481 /* Registers FREE to be called with argument P.
482 P should be unique among those registered in POOL so that it can be
483 uniquely identified by pool_unregister().
484 If not unregistered, FREE will be called with argument P when POOL
487 pool_register (struct pool *pool, void (*free) (void *), void *p)
489 assert (pool && free && p);
492 struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
493 g->type = POOL_GIZMO_REGISTERED;
494 g->p.registered.free = free;
495 g->p.registered.p = p;
500 /* Unregisters previously registered P from POOL.
501 Returns nonzero only if P was found to be registered in POOL. */
503 pool_unregister (struct pool *pool, void *p)
508 struct pool_gizmo *g;
510 for (g = pool->gizmos; g; g = g->next)
511 if (g->type == POOL_GIZMO_REGISTERED && g->p.registered.p == p)
513 delete_gizmo (pool, g);
521 /* Partial freeing. */
523 /* Notes the state of POOL into MARK so that it may be restored
524 by a call to pool_release(). */
526 pool_mark (struct pool *pool, struct pool_mark *mark)
528 assert (pool && mark);
530 mark->block = pool->blocks;
531 mark->ofs = pool->blocks->ofs;
533 mark->serial = serial;
536 /* Restores to POOL the state recorded in MARK.
537 Emptied blocks are not given back with free() but kept for
538 later allocations. To get that behavior, use a subpool
541 pool_release (struct pool *pool, const struct pool_mark *mark)
543 assert (pool && mark);
546 struct pool_gizmo *cur, *next;
548 for (cur = pool->gizmos; cur && cur->serial >= mark->serial; cur = next)
564 struct pool_block *cur;
566 for (cur = pool->blocks; cur != mark->block; cur = cur->next)
568 cur->ofs = POOL_BLOCK_SIZE;
569 if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
570 cur->ofs += POOL_SIZE;
572 pool->blocks = mark->block;
573 pool->blocks->ofs = mark->ofs;
577 /* Private functions. */
579 /* Adds GIZMO at the beginning of POOL's gizmo list. */
581 add_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
583 assert (pool && gizmo);
585 gizmo->next = pool->gizmos;
588 pool->gizmos->prev = gizmo;
589 pool->gizmos = gizmo;
591 gizmo->serial = serial++;
594 /* Removes GIZMO from POOL's gizmo list. */
596 delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
598 assert (pool && gizmo);
601 gizmo->prev->next = gizmo->next;
603 pool->gizmos = gizmo->next;
605 gizmo->next->prev = gizmo->prev;
608 /* Frees any of GIZMO's internal state.
609 GIZMO's data must not be referenced after calling this function. */
611 free_gizmo (struct pool_gizmo *gizmo)
613 assert (gizmo != NULL);
617 case POOL_GIZMO_MALLOC:
620 case POOL_GIZMO_FILE:
621 fclose (gizmo->p.file); /* Ignore errors. */
623 case POOL_GIZMO_SUBPOOL:
624 gizmo->p.subpool->parent = NULL;
625 pool_destroy (gizmo->p.subpool);
627 case POOL_GIZMO_REGISTERED:
628 gizmo->p.registered.free (gizmo->p.registered.p);
635 /* Free all the gizmos in POOL. */
637 free_all_gizmos (struct pool *pool)
639 struct pool_gizmo *cur, *next;
641 for (cur = pool->gizmos; cur; cur = next)
649 /* Memory allocation. */
652 /* Allocates SIZE bytes of space using malloc(). Aborts if out of
655 xmalloc (size_t size)
667 /* Reallocates P to be SIZE bytes long using realloc(). Aborts if out
670 xrealloc (void *p, size_t size)
673 return xmalloc (size);
679 p = realloc (p, size);
686 /* Self-test routine. */
695 #define N_ITERATIONS 8192
698 /* Self-test routine.
699 This is not exhaustive, but it can be useful. */
701 main (int argc, char **argv)
706 seed = atoi (argv[1]);
708 seed = time (0) * 257 % 32768;
713 struct pool_mark m1, m2;
714 FILE *files[N_FILES];
718 printf ("Random number seed: %d\n", seed);
721 printf ("Creating pool...\n");
722 pool = pool_create ();
724 printf ("Marking pool state...\n");
725 pool_mark (pool, &m1);
727 printf (" Populating pool with random-sized small objects...\n");
728 for (i = 0; i < N_ITERATIONS; i++)
730 size_t size = rand () % MAX_SUBALLOC;
731 void *p = pool_alloc (pool, size);
735 printf (" Marking pool state...\n");
736 pool_mark (pool, &m2);
738 printf (" Populating pool with random-sized small "
739 "and large objects...\n");
740 for (i = 0; i < N_ITERATIONS; i++)
742 size_t size = rand () % (2 * MAX_SUBALLOC);
743 void *p = pool_alloc (pool, size);
747 printf (" Releasing pool state...\n");
748 pool_release (pool, &m2);
750 printf (" Populating pool with random objects and gizmos...\n");
751 for (i = 0; i < N_FILES; i++)
754 for (i = 0; i < N_ITERATIONS; i++)
756 int type = rand () % 32;
760 if (files[cur_file] != NULL
761 && EOF == pool_fclose (pool, files[cur_file]))
762 printf ("error on fclose: %s\n", strerror (errno));
764 files[cur_file] = pool_fopen (pool, "/dev/null", "r");
766 if (++cur_file >= N_FILES)
770 pool_create_subpool (pool);
773 size_t size = rand () % (2 * MAX_SUBALLOC);
774 void *p = pool_alloc (pool, size);
779 printf ("Releasing pool state...\n");
780 pool_release (pool, &m1);
782 printf ("Destroying pool...\n");
789 #endif /* SELF_TEST */
793 compile-command: "gcc -DSELF_TEST=1 -W -Wall -I. -o pool_test pool.c"