Clean up pref.h.orig and deal with the consequences.
[pspp-builds.git] / src / pool.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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
18    02111-1307, USA. */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include "pool.h"
24 #include <assert.h>
25 #include <stdlib.h>
26 #include "alloc.h"
27 #include "str.h"
28
29 /* Fast, low-overhead memory block suballocator. */
30 struct pool
31   {
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. */
35   };
36
37 /* Pool block. */
38 struct pool_block 
39   {
40     struct pool_block *prev;
41     struct pool_block *next;
42     size_t ofs;
43   };
44
45 /* Gizmo types. */
46 enum
47   {
48     POOL_GIZMO_MALLOC,
49     POOL_GIZMO_FILE,
50     POOL_GIZMO_SUBPOOL,
51     POOL_GIZMO_REGISTERED,
52   };
53
54 /* Pool routines can maintain objects (`gizmos') as well as doing
55    suballocation.  
56    This structure is used to keep track of them. */
57 struct pool_gizmo
58   {
59     struct pool_gizmo *prev;
60     struct pool_gizmo *next;
61
62     long serial;                /* Serial number. */
63     int type;                   /* Type of this gizmo. */
64
65     /* Type-dependent info. */
66     union
67       {
68         FILE *file;             /* POOL_GIZMO_FILE. */
69         struct pool *subpool;   /* POOL_GIZMO_SUBPOOL. */
70
71         /* POOL_GIZMO_REGISTERED. */
72         struct
73           {
74             void (*free) (void *p);
75             void *p;
76           }
77         registered;
78       }
79     p;
80   };
81
82 /* Rounds X up to the next multiple of Y. */
83 #ifndef ROUND_UP
84 #define ROUND_UP(X, Y)                          \
85         (((X) + ((Y) - 1)) / (Y) * (Y))
86 #endif
87
88 /* Types that provide typically useful alignment sizes. */
89 union align
90   {
91     void *op;
92     void (*fp) (void);
93     long l;
94     double d;
95   };
96
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. */
101 #else
102 #define ALIGN_SIZE sizeof (union align)
103 #endif
104
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.
109
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*/
114
115 /* Enable debug code if appropriate. */
116 #if SELF_TEST
117 #endif
118
119 /* Size of each block allocated in the pool, in bytes.
120    Should be at least 1k. */
121 #ifndef BLOCK_SIZE
122 #define BLOCK_SIZE 1024
123 #endif
124
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. */
128 #ifndef MAX_SUBALLOC
129 #define MAX_SUBALLOC 64
130 #endif
131
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)
136
137 /* Serial number used to keep track of gizmos for mark/release. */
138 static long serial = 0;
139
140 /* Prototypes. */
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 *);
145
146 #if !PSPP
147 static void *xmalloc (size_t);
148 static void *xrealloc (void *, size_t);
149 #endif
150 \f
151 /* General routines. */
152
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.
156
157    In addition, other objects can be associated with a memory pool.
158    These are released when the pool is destroyed. */
159 struct pool *
160 pool_create (void)
161 {
162   struct pool_block *block;
163   struct pool *pool;
164
165   block = xmalloc (BLOCK_SIZE);
166   block->prev = block->next = block;
167   block->ofs = POOL_BLOCK_SIZE + POOL_SIZE;
168   
169   pool = (struct pool *) (((char *) block) + POOL_BLOCK_SIZE);
170   pool->parent = NULL;
171   pool->blocks = block;
172   pool->gizmos = NULL;
173
174   return pool;
175 }
176
177 /* Destroy the specified pool, including all subpools. */
178 void
179 pool_destroy (struct pool *pool)
180 {
181   if (pool == NULL)
182     return;
183
184   /* Remove this pool from its parent's list of gizmos. */
185   if (pool->parent) 
186     delete_gizmo (pool->parent,
187                   (void *) (((char *) pool) + POOL_SIZE + POOL_BLOCK_SIZE));
188
189   free_all_gizmos (pool);
190
191   /* Free all the memory. */
192   {
193     struct pool_block *cur, *next;
194
195     pool->blocks->prev->next = NULL;
196     for (cur = pool->blocks; cur; cur = next)
197       {
198         next = cur->next;
199         free (cur);
200       }
201   }
202 }
203
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. */ 
207 void
208 pool_clear (struct pool *pool) 
209 {
210   free_all_gizmos (pool);
211
212   /* Zero out block sizes. */
213   {
214     struct pool_block *cur;
215     
216     cur = pool->blocks;
217     do
218       {
219         cur->ofs = POOL_BLOCK_SIZE;
220         if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
221           cur->ofs += POOL_SIZE;
222         cur = cur->next;
223       }
224     while (cur != pool->blocks);
225   }
226 }
227 \f
228 /* Suballocation routines. */
229
230 /* Allocates a memory region AMT bytes in size from POOL and returns a
231    pointer to the region's start. */
232 void *
233 pool_alloc (struct pool *pool, size_t amt)
234 {
235   assert (pool != NULL);
236   
237 #ifndef DISCRETE_BLOCKS
238   if (amt <= MAX_SUBALLOC)
239     {
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)
244         {
245           void *const p = ((char *) b) + b->ofs;
246           b->ofs += amt;
247           return p;
248         }
249
250       /* No space in this block, so we must make other
251          arrangements. */
252       if (b->next->ofs == 0) 
253         {
254           /* The next block is empty.  Use it. */
255           b = b->next;
256           b->ofs = POOL_BLOCK_SIZE;
257           if ((char *) b + POOL_BLOCK_SIZE == (char *) pool)
258             b->ofs += POOL_SIZE;
259         }
260       else 
261         {
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;
269         }
270       pool->blocks = b;
271
272       /* Allocate space from B. */
273       b->ofs += amt;
274       return ((char *) b) + b->ofs - amt;
275     }
276   else
277 #endif
278     return pool_malloc (pool, amt);
279 }
280
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. */
286 char *
287 pool_strndup (struct pool *pool, const char *string, size_t length)
288 {
289   size_t size;
290   char *copy;
291
292   assert (pool && string);
293   size = length + 1;
294
295   /* Note that strings need not be aligned on any boundary. */
296 #ifndef DISCRETE_BLOCKS
297   {
298     struct pool_block *const b = pool->blocks;
299
300     if (b->ofs + size <= BLOCK_SIZE)
301       {
302         copy = ((char *) b) + b->ofs;
303         b->ofs += size;
304       }
305   }
306 #else
307   copy = pool_alloc (pool, size);
308 #endif
309
310   memcpy (copy, string, length);
311   copy[length] = '\0';
312   return copy;
313 }
314
315 /* Duplicates null-terminated STRING, within POOL, and returns a
316    pointer to the duplicate.  For use only with strings, because
317    the returned pointere may not be aligned properly for other
318    types. */
319 char *
320 pool_strdup (struct pool *pool, const char *string) 
321 {
322   return pool_strndup (pool, string, strlen (string));
323 }
324 \f
325 /* Standard allocation routines. */
326
327 /* Allocates AMT bytes using malloc(), to be managed by POOL, and
328    returns a pointer to the beginning of the block.
329    If POOL is a null pointer, then allocates a normal memory block
330    with malloc().  */
331 void *
332 pool_malloc (struct pool *pool, size_t amt)
333 {
334   if (pool != NULL)
335     {
336       if (amt != 0)
337         {
338           struct pool_gizmo *g = xmalloc (amt + POOL_GIZMO_SIZE);
339           g->type = POOL_GIZMO_MALLOC;
340           add_gizmo (pool, g);
341
342           return ((char *) g) + POOL_GIZMO_SIZE;
343         }
344       else
345         return NULL;
346     }
347   else
348     return xmalloc (amt);
349 }
350
351 /* Changes the allocation size of the specified memory block P managed
352    by POOL to AMT bytes and returns a pointer to the beginning of the
353    block.
354    If POOL is a null pointer, then the block is reallocated in the
355    usual way with realloc(). */
356 void *
357 pool_realloc (struct pool *pool, void *p, size_t amt)
358 {
359   if (pool != NULL)
360     {
361       if (p != NULL)
362         {
363           if (amt != 0)
364             {
365               struct pool_gizmo *g;
366
367               g = xrealloc (((char *) p) - POOL_GIZMO_SIZE,
368                             amt + POOL_GIZMO_SIZE);
369               if (g->next)
370                 g->next->prev = g;
371               if (g->prev)
372                 g->prev->next = g;
373               else
374                 pool->gizmos = g;
375
376               return ((char *) g) + POOL_GIZMO_SIZE;
377             }
378           else
379             {
380               pool_free (pool, p);
381               return NULL;
382             }
383         }
384       else
385         return pool_malloc (pool, amt);
386     }
387   else
388     return xrealloc (p, amt);
389 }
390
391 /* Frees block P managed by POOL.
392    If POOL is a null pointer, then the block is freed as usual with
393    free(). */
394 void
395 pool_free (struct pool *pool, void *p)
396 {
397   if (pool != NULL && p != NULL)
398     {
399       struct pool_gizmo *g = (void *) (((char *) p) - POOL_GIZMO_SIZE);
400       delete_gizmo (pool, g);
401       free (g);
402     }
403   else
404     free (p);
405 }
406 \f
407 /* Gizmo allocations. */
408
409 /* Creates and returns a pool as a subpool of POOL.
410    The subpool will be destroyed automatically when POOL is destroyed.
411    It may also be destroyed explicitly in advance. */
412 struct pool *
413 pool_create_subpool (struct pool *pool)
414 {
415   struct pool *subpool;
416   struct pool_gizmo *g;
417
418   assert (pool != NULL);
419   subpool = pool_create ();
420   subpool->parent = pool;
421
422   g = (void *) (((char *) subpool) + subpool->blocks->ofs);
423   subpool->blocks->ofs += POOL_GIZMO_SIZE;
424   
425   g->type = POOL_GIZMO_SUBPOOL;
426   g->p.subpool = subpool;
427
428   add_gizmo (pool, g);
429
430   return subpool;
431 }
432
433 /* Opens file FILENAME with mode MODE and returns a handle to it
434    if successful or a null pointer if not.
435    The file will be closed automatically when POOL is destroyed, or it
436    may be closed explicitly in advance using pool_fclose. */
437 FILE *
438 pool_fopen (struct pool *pool, const char *filename, const char *mode)
439 {
440   FILE *f;
441
442   assert (pool && filename && mode);
443   f = fopen (filename, mode);
444   if (f == NULL)
445     return NULL;
446
447   {
448     struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
449     g->type = POOL_GIZMO_FILE;
450     g->p.file = f;
451     add_gizmo (pool, g);
452   }
453
454   return f;
455 }
456
457 /* Closes file FILE managed by POOL. */
458 int
459 pool_fclose (struct pool *pool, FILE *file)
460 {
461   assert (pool && file);
462   if (fclose (file) == EOF)
463     return EOF;
464   
465   {
466     struct pool_gizmo *g;
467
468     for (g = pool->gizmos; g; g = g->next)
469       if (g->type == POOL_GIZMO_FILE && g->p.file == file)
470         {
471           delete_gizmo (pool, g);
472           break;
473         }
474   }
475   
476   return 0;
477 }
478 \f
479 /* Registers FREE to be called with argument P.
480    P should be unique among those registered in POOL so that it can be
481    uniquely identified by pool_unregister().
482    If not unregistered, FREE will be called with argument P when POOL
483    is destroyed. */
484 void
485 pool_register (struct pool *pool, void (*free) (void *), void *p)
486 {
487   assert (pool && free && p);
488
489   {
490     struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
491     g->type = POOL_GIZMO_REGISTERED;
492     g->p.registered.free = free;
493     g->p.registered.p = p;
494     add_gizmo (pool, g);
495   }
496 }
497
498 /* Unregisters previously registered P from POOL.
499    Returns nonzero only if P was found to be registered in POOL. */
500 int
501 pool_unregister (struct pool *pool, void *p)
502 {
503   assert (pool && p);
504   
505   {
506     struct pool_gizmo *g;
507
508     for (g = pool->gizmos; g; g = g->next)
509       if (g->type == POOL_GIZMO_REGISTERED && g->p.registered.p == p)
510         {
511           delete_gizmo (pool, g);
512           return 1;
513         }
514   }
515   
516   return 0;
517 }
518 \f
519 /* Partial freeing. */
520
521 /* Notes the state of POOL into MARK so that it may be restored
522    by a call to pool_release(). */
523 void
524 pool_mark (struct pool *pool, struct pool_mark *mark)
525 {
526   assert (pool && mark);
527
528   mark->block = pool->blocks;
529   mark->ofs = pool->blocks->ofs;
530
531   mark->serial = serial;
532 }
533
534 /* Restores to POOL the state recorded in MARK.
535    Emptied blocks are not given back with free() but kept for
536    later allocations.  To get that behavior, use a subpool
537    instead. */ 
538 void
539 pool_release (struct pool *pool, const struct pool_mark *mark)
540 {
541   assert (pool && mark);
542   
543   {
544     struct pool_gizmo *cur, *next;
545
546     for (cur = pool->gizmos; cur && cur->serial >= mark->serial; cur = next)
547       {
548         next = cur->next;
549         free_gizmo (cur);
550       }
551
552     if (cur != NULL)
553       {
554         cur->prev = NULL;
555         pool->gizmos = cur;
556       }
557     else
558       pool->gizmos = NULL;
559   }
560   
561   {
562     struct pool_block *cur;
563
564     for (cur = pool->blocks; cur != mark->block; cur = cur->next) 
565       {
566         cur->ofs = POOL_BLOCK_SIZE;
567         if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
568           cur->ofs += POOL_SIZE; 
569       }
570     pool->blocks = mark->block;
571     pool->blocks->ofs = mark->ofs;
572   }
573 }
574 \f
575 /* Private functions. */
576
577 /* Adds GIZMO at the beginning of POOL's gizmo list. */
578 static void
579 add_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
580 {
581   assert (pool && gizmo);
582   
583   gizmo->next = pool->gizmos;
584   gizmo->prev = NULL;
585   if (pool->gizmos)
586     pool->gizmos->prev = gizmo;
587   pool->gizmos = gizmo;
588
589   gizmo->serial = serial++;
590 }
591  
592 /* Removes GIZMO from POOL's gizmo list. */
593 static void
594 delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
595 {
596   assert (pool && gizmo);
597   
598   if (gizmo->prev)
599     gizmo->prev->next = gizmo->next;
600   else
601     pool->gizmos = gizmo->next;
602   if (gizmo->next)
603     gizmo->next->prev = gizmo->prev;
604 }
605
606 /* Frees any of GIZMO's internal state.
607    GIZMO's data must not be referenced after calling this function. */
608 static void
609 free_gizmo (struct pool_gizmo *gizmo)
610 {
611   assert (gizmo != NULL);
612   
613   switch (gizmo->type)
614     {
615     case POOL_GIZMO_MALLOC:
616       free (gizmo);
617       break;
618     case POOL_GIZMO_FILE:
619       fclose (gizmo->p.file);   /* Ignore errors. */
620       break;
621     case POOL_GIZMO_SUBPOOL:
622       gizmo->p.subpool->parent = NULL;
623       pool_destroy (gizmo->p.subpool);
624       break;
625     case POOL_GIZMO_REGISTERED:
626       gizmo->p.registered.free (gizmo->p.registered.p);
627       break;
628     default:
629       assert (0);
630     }
631 }
632
633 /* Free all the gizmos in POOL. */
634 static void
635 free_all_gizmos (struct pool *pool) 
636 {
637   struct pool_gizmo *cur, *next;
638
639   for (cur = pool->gizmos; cur; cur = next)
640     {
641       next = cur->next;
642       free_gizmo (cur);
643     }
644 }
645 \f
646 /* Memory allocation. */
647
648 #if !PSPP
649 /* Allocates SIZE bytes of space using malloc().  Aborts if out of
650    memory. */
651 static void *
652 xmalloc (size_t size)
653 {
654   void *vp;
655   if (size == 0)
656     return NULL;
657   vp = malloc (size);
658   assert (vp != NULL);
659   if (vp == NULL)
660     abort ();
661   return vp;
662 }
663
664 /* Reallocates P to be SIZE bytes long using realloc().  Aborts if out
665    of memory. */
666 static void *
667 xrealloc (void *p, size_t size)
668 {
669   if (p == NULL)
670     return xmalloc (size);
671   if (size == 0)
672     {
673       free (p);
674       return NULL;
675     }
676   p = realloc (p, size);
677   if (p == NULL)
678     abort ();
679   return p;
680 }
681 #endif /* !PSPP */
682 \f
683 /* Self-test routine. */
684
685 #if SELF_TEST
686 #include <errno.h>
687 #include <stdio.h>
688 #include <stdlib.h>
689 #include <string.h>
690 #include <time.h>
691
692 #define N_ITERATIONS 8192
693 #define N_FILES 16
694
695 /* Self-test routine.
696    This is not exhaustive, but it can be useful. */
697 int
698 main (int argc, char **argv)
699 {
700   int seed;
701   
702   if (argc == 2)
703     seed = atoi (argv[1]);
704   else
705     seed = time (0) * 257 % 32768;
706
707   for (;;)
708     {
709       struct pool *pool;
710       struct pool_mark m1, m2;
711       FILE *files[N_FILES];
712       int cur_file;
713       long i;
714
715       printf ("Random number seed: %d\n", seed);
716       srand (seed++);
717
718       printf ("Creating pool...\n");
719       pool = pool_create ();
720
721       printf ("Marking pool state...\n");
722       pool_mark (pool, &m1);
723
724       printf ("    Populating pool with random-sized small objects...\n");
725       for (i = 0; i < N_ITERATIONS; i++)
726         {
727           size_t size = rand () % MAX_SUBALLOC;
728           void *p = pool_alloc (pool, size);
729           memset (p, 0, size);
730         }
731
732       printf ("    Marking pool state...\n");
733       pool_mark (pool, &m2);
734       
735       printf ("       Populating pool with random-sized small "
736               "and large objects...\n");
737       for (i = 0; i < N_ITERATIONS; i++)
738         {
739           size_t size = rand () % (2 * MAX_SUBALLOC);
740           void *p = pool_alloc (pool, size);
741           memset (p, 0, size);
742         }
743
744       printf ("    Releasing pool state...\n");
745       pool_release (pool, &m2);
746
747       printf ("    Populating pool with random objects and gizmos...\n");
748       for (i = 0; i < N_FILES; i++)
749         files[i] = NULL;
750       cur_file = 0;
751       for (i = 0; i < N_ITERATIONS; i++)
752         {
753           int type = rand () % 32;
754
755           if (type == 0)
756             {
757               if (files[cur_file] != NULL
758                   && EOF == pool_fclose (pool, files[cur_file]))
759                 printf ("error on fclose: %s\n", strerror (errno));
760
761               files[cur_file] = pool_fopen (pool, "/dev/null", "r");
762
763               if (++cur_file >= N_FILES)
764                 cur_file = 0;
765             }
766           else if (type == 1)
767             pool_create_subpool (pool);
768           else 
769             {
770               size_t size = rand () % (2 * MAX_SUBALLOC);
771               void *p = pool_alloc (pool, size);
772               memset (p, 0, size);
773             }
774         }
775       
776       printf ("Releasing pool state...\n");
777       pool_release (pool, &m1);
778
779       printf ("Destroying pool...\n");
780       pool_destroy (pool);
781
782       putchar ('\n');
783     }
784 }
785
786 #endif /* SELF_TEST */
787
788 /* 
789    Local variables:
790    compile-command: "gcc -DSELF_TEST=1 -W -Wall -I. -o pool_test pool.c"
791    End:
792 */