Home | History | Annotate | Line # | Download | only in libiberty
objalloc.c revision 1.1
      1  1.1  skrll /* objalloc.c -- routines to allocate memory for objects
      2  1.1  skrll    Copyright 1997 Free Software Foundation, Inc.
      3  1.1  skrll    Written by Ian Lance Taylor, Cygnus Solutions.
      4  1.1  skrll 
      5  1.1  skrll This program is free software; you can redistribute it and/or modify it
      6  1.1  skrll under the terms of the GNU General Public License as published by the
      7  1.1  skrll Free Software Foundation; either version 2, or (at your option) any
      8  1.1  skrll later version.
      9  1.1  skrll 
     10  1.1  skrll This program is distributed in the hope that it will be useful,
     11  1.1  skrll but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  skrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  skrll GNU General Public License for more details.
     14  1.1  skrll 
     15  1.1  skrll You should have received a copy of the GNU General Public License
     16  1.1  skrll along with this program; if not, write to the Free Software
     17  1.1  skrll Foundation, 51 Franklin Street - Fifth Floor,
     18  1.1  skrll Boston, MA 02110-1301, USA.  */
     19  1.1  skrll 
     20  1.1  skrll #include "config.h"
     21  1.1  skrll #include "ansidecl.h"
     22  1.1  skrll 
     23  1.1  skrll #include "objalloc.h"
     24  1.1  skrll 
     25  1.1  skrll /* Get a definition for NULL.  */
     26  1.1  skrll #include <stdio.h>
     27  1.1  skrll 
     28  1.1  skrll #if VMS
     29  1.1  skrll #include <stdlib.h>
     30  1.1  skrll #include <unixlib.h>
     31  1.1  skrll #else
     32  1.1  skrll 
     33  1.1  skrll /* Get a definition for size_t.  */
     34  1.1  skrll #include <stddef.h>
     35  1.1  skrll 
     36  1.1  skrll #ifdef HAVE_STDLIB_H
     37  1.1  skrll #include <stdlib.h>
     38  1.1  skrll #else
     39  1.1  skrll /* For systems with larger pointers than ints, this must be declared.  */
     40  1.1  skrll extern PTR malloc (size_t);
     41  1.1  skrll extern void free (PTR);
     42  1.1  skrll #endif
     43  1.1  skrll 
     44  1.1  skrll #endif
     45  1.1  skrll 
     46  1.1  skrll /* These routines allocate space for an object.  Freeing allocated
     47  1.1  skrll    space may or may not free all more recently allocated space.
     48  1.1  skrll 
     49  1.1  skrll    We handle large and small allocation requests differently.  If we
     50  1.1  skrll    don't have enough space in the current block, and the allocation
     51  1.1  skrll    request is for more than 512 bytes, we simply pass it through to
     52  1.1  skrll    malloc.  */
     53  1.1  skrll 
     54  1.1  skrll /* The objalloc structure is defined in objalloc.h.  */
     55  1.1  skrll 
     56  1.1  skrll /* This structure appears at the start of each chunk.  */
     57  1.1  skrll 
     58  1.1  skrll struct objalloc_chunk
     59  1.1  skrll {
     60  1.1  skrll   /* Next chunk.  */
     61  1.1  skrll   struct objalloc_chunk *next;
     62  1.1  skrll   /* If this chunk contains large objects, this is the value of
     63  1.1  skrll      current_ptr when this chunk was allocated.  If this chunk
     64  1.1  skrll      contains small objects, this is NULL.  */
     65  1.1  skrll   char *current_ptr;
     66  1.1  skrll };
     67  1.1  skrll 
     68  1.1  skrll /* The aligned size of objalloc_chunk.  */
     69  1.1  skrll 
     70  1.1  skrll #define CHUNK_HEADER_SIZE					\
     71  1.1  skrll   ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1)	\
     72  1.1  skrll    &~ (OBJALLOC_ALIGN - 1))
     73  1.1  skrll 
     74  1.1  skrll /* We ask for this much memory each time we create a chunk which is to
     75  1.1  skrll    hold small objects.  */
     76  1.1  skrll 
     77  1.1  skrll #define CHUNK_SIZE (4096 - 32)
     78  1.1  skrll 
     79  1.1  skrll /* A request for this amount or more is just passed through to malloc.  */
     80  1.1  skrll 
     81  1.1  skrll #define BIG_REQUEST (512)
     82  1.1  skrll 
     83  1.1  skrll /* Create an objalloc structure.  */
     84  1.1  skrll 
     85  1.1  skrll struct objalloc *
     86  1.1  skrll objalloc_create (void)
     87  1.1  skrll {
     88  1.1  skrll   struct objalloc *ret;
     89  1.1  skrll   struct objalloc_chunk *chunk;
     90  1.1  skrll 
     91  1.1  skrll   ret = (struct objalloc *) malloc (sizeof *ret);
     92  1.1  skrll   if (ret == NULL)
     93  1.1  skrll     return NULL;
     94  1.1  skrll 
     95  1.1  skrll   ret->chunks = (PTR) malloc (CHUNK_SIZE);
     96  1.1  skrll   if (ret->chunks == NULL)
     97  1.1  skrll     {
     98  1.1  skrll       free (ret);
     99  1.1  skrll       return NULL;
    100  1.1  skrll     }
    101  1.1  skrll 
    102  1.1  skrll   chunk = (struct objalloc_chunk *) ret->chunks;
    103  1.1  skrll   chunk->next = NULL;
    104  1.1  skrll   chunk->current_ptr = NULL;
    105  1.1  skrll 
    106  1.1  skrll   ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
    107  1.1  skrll   ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
    108  1.1  skrll 
    109  1.1  skrll   return ret;
    110  1.1  skrll }
    111  1.1  skrll 
    112  1.1  skrll /* Allocate space from an objalloc structure.  */
    113  1.1  skrll 
    114  1.1  skrll PTR
    115  1.1  skrll _objalloc_alloc (struct objalloc *o, unsigned long len)
    116  1.1  skrll {
    117  1.1  skrll   /* We avoid confusion from zero sized objects by always allocating
    118  1.1  skrll      at least 1 byte.  */
    119  1.1  skrll   if (len == 0)
    120  1.1  skrll     len = 1;
    121  1.1  skrll 
    122  1.1  skrll   len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1);
    123  1.1  skrll 
    124  1.1  skrll   if (len <= o->current_space)
    125  1.1  skrll     {
    126  1.1  skrll       o->current_ptr += len;
    127  1.1  skrll       o->current_space -= len;
    128  1.1  skrll       return (PTR) (o->current_ptr - len);
    129  1.1  skrll     }
    130  1.1  skrll 
    131  1.1  skrll   if (len >= BIG_REQUEST)
    132  1.1  skrll     {
    133  1.1  skrll       char *ret;
    134  1.1  skrll       struct objalloc_chunk *chunk;
    135  1.1  skrll 
    136  1.1  skrll       ret = (char *) malloc (CHUNK_HEADER_SIZE + len);
    137  1.1  skrll       if (ret == NULL)
    138  1.1  skrll 	return NULL;
    139  1.1  skrll 
    140  1.1  skrll       chunk = (struct objalloc_chunk *) ret;
    141  1.1  skrll       chunk->next = (struct objalloc_chunk *) o->chunks;
    142  1.1  skrll       chunk->current_ptr = o->current_ptr;
    143  1.1  skrll 
    144  1.1  skrll       o->chunks = (PTR) chunk;
    145  1.1  skrll 
    146  1.1  skrll       return (PTR) (ret + CHUNK_HEADER_SIZE);
    147  1.1  skrll     }
    148  1.1  skrll   else
    149  1.1  skrll     {
    150  1.1  skrll       struct objalloc_chunk *chunk;
    151  1.1  skrll 
    152  1.1  skrll       chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE);
    153  1.1  skrll       if (chunk == NULL)
    154  1.1  skrll 	return NULL;
    155  1.1  skrll       chunk->next = (struct objalloc_chunk *) o->chunks;
    156  1.1  skrll       chunk->current_ptr = NULL;
    157  1.1  skrll 
    158  1.1  skrll       o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
    159  1.1  skrll       o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
    160  1.1  skrll 
    161  1.1  skrll       o->chunks = (PTR) chunk;
    162  1.1  skrll 
    163  1.1  skrll       return objalloc_alloc (o, len);
    164  1.1  skrll     }
    165  1.1  skrll }
    166  1.1  skrll 
    167  1.1  skrll /* Free an entire objalloc structure.  */
    168  1.1  skrll 
    169  1.1  skrll void
    170  1.1  skrll objalloc_free (struct objalloc *o)
    171  1.1  skrll {
    172  1.1  skrll   struct objalloc_chunk *l;
    173  1.1  skrll 
    174  1.1  skrll   l = (struct objalloc_chunk *) o->chunks;
    175  1.1  skrll   while (l != NULL)
    176  1.1  skrll     {
    177  1.1  skrll       struct objalloc_chunk *next;
    178  1.1  skrll 
    179  1.1  skrll       next = l->next;
    180  1.1  skrll       free (l);
    181  1.1  skrll       l = next;
    182  1.1  skrll     }
    183  1.1  skrll 
    184  1.1  skrll   free (o);
    185  1.1  skrll }
    186  1.1  skrll 
    187  1.1  skrll /* Free a block from an objalloc structure.  This also frees all more
    188  1.1  skrll    recently allocated blocks.  */
    189  1.1  skrll 
    190  1.1  skrll void
    191  1.1  skrll objalloc_free_block (struct objalloc *o, PTR block)
    192  1.1  skrll {
    193  1.1  skrll   struct objalloc_chunk *p, *small;
    194  1.1  skrll   char *b = (char *) block;
    195  1.1  skrll 
    196  1.1  skrll   /* First set P to the chunk which contains the block we are freeing,
    197  1.1  skrll      and set Q to the last small object chunk we see before P.  */
    198  1.1  skrll   small = NULL;
    199  1.1  skrll   for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
    200  1.1  skrll     {
    201  1.1  skrll       if (p->current_ptr == NULL)
    202  1.1  skrll 	{
    203  1.1  skrll 	  if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
    204  1.1  skrll 	    break;
    205  1.1  skrll 	  small = p;
    206  1.1  skrll 	}
    207  1.1  skrll       else
    208  1.1  skrll 	{
    209  1.1  skrll 	  if (b == (char *) p + CHUNK_HEADER_SIZE)
    210  1.1  skrll 	    break;
    211  1.1  skrll 	}
    212  1.1  skrll     }
    213  1.1  skrll 
    214  1.1  skrll   /* If we can't find the chunk, the caller has made a mistake.  */
    215  1.1  skrll   if (p == NULL)
    216  1.1  skrll     abort ();
    217  1.1  skrll 
    218  1.1  skrll   if (p->current_ptr == NULL)
    219  1.1  skrll     {
    220  1.1  skrll       struct objalloc_chunk *q;
    221  1.1  skrll       struct objalloc_chunk *first;
    222  1.1  skrll 
    223  1.1  skrll       /* The block is in a chunk containing small objects.  We can
    224  1.1  skrll 	 free every chunk through SMALL, because they have certainly
    225  1.1  skrll 	 been allocated more recently.  After SMALL, we will not see
    226  1.1  skrll 	 any chunks containing small objects; we can free any big
    227  1.1  skrll 	 chunk if the current_ptr is greater than or equal to B.  We
    228  1.1  skrll 	 can then reset the new current_ptr to B.  */
    229  1.1  skrll 
    230  1.1  skrll       first = NULL;
    231  1.1  skrll       q = (struct objalloc_chunk *) o->chunks;
    232  1.1  skrll       while (q != p)
    233  1.1  skrll 	{
    234  1.1  skrll 	  struct objalloc_chunk *next;
    235  1.1  skrll 
    236  1.1  skrll 	  next = q->next;
    237  1.1  skrll 	  if (small != NULL)
    238  1.1  skrll 	    {
    239  1.1  skrll 	      if (small == q)
    240  1.1  skrll 		small = NULL;
    241  1.1  skrll 	      free (q);
    242  1.1  skrll 	    }
    243  1.1  skrll 	  else if (q->current_ptr > b)
    244  1.1  skrll 	    free (q);
    245  1.1  skrll 	  else if (first == NULL)
    246  1.1  skrll 	    first = q;
    247  1.1  skrll 
    248  1.1  skrll 	  q = next;
    249  1.1  skrll 	}
    250  1.1  skrll 
    251  1.1  skrll       if (first == NULL)
    252  1.1  skrll 	first = p;
    253  1.1  skrll       o->chunks = (PTR) first;
    254  1.1  skrll 
    255  1.1  skrll       /* Now start allocating from this small block again.  */
    256  1.1  skrll       o->current_ptr = b;
    257  1.1  skrll       o->current_space = ((char *) p + CHUNK_SIZE) - b;
    258  1.1  skrll     }
    259  1.1  skrll   else
    260  1.1  skrll     {
    261  1.1  skrll       struct objalloc_chunk *q;
    262  1.1  skrll       char *current_ptr;
    263  1.1  skrll 
    264  1.1  skrll       /* This block is in a large chunk by itself.  We can free
    265  1.1  skrll          everything on the list up to and including this block.  We
    266  1.1  skrll          then start allocating from the next chunk containing small
    267  1.1  skrll          objects, setting current_ptr from the value stored with the
    268  1.1  skrll          large chunk we are freeing.  */
    269  1.1  skrll 
    270  1.1  skrll       current_ptr = p->current_ptr;
    271  1.1  skrll       p = p->next;
    272  1.1  skrll 
    273  1.1  skrll       q = (struct objalloc_chunk *) o->chunks;
    274  1.1  skrll       while (q != p)
    275  1.1  skrll 	{
    276  1.1  skrll 	  struct objalloc_chunk *next;
    277  1.1  skrll 
    278  1.1  skrll 	  next = q->next;
    279  1.1  skrll 	  free (q);
    280  1.1  skrll 	  q = next;
    281  1.1  skrll 	}
    282  1.1  skrll 
    283  1.1  skrll       o->chunks = (PTR) p;
    284  1.1  skrll 
    285  1.1  skrll       while (p->current_ptr != NULL)
    286  1.1  skrll 	p = p->next;
    287  1.1  skrll 
    288  1.1  skrll       o->current_ptr = current_ptr;
    289  1.1  skrll       o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
    290  1.1  skrll     }
    291  1.1  skrll }
    292