Home | History | Annotate | Line # | Download | only in lib
      1  1.1       agc /*
      2  1.1       agc   tre-mem.c - TRE memory allocator
      3  1.1       agc 
      4  1.1       agc   This software is released under a BSD-style license.
      5  1.1       agc   See the file LICENSE for details and copyright.
      6  1.1       agc 
      7  1.1       agc */
      8  1.1       agc 
      9  1.1       agc /*
     10  1.1       agc   This memory allocator is for allocating small memory blocks efficiently
     11  1.1       agc   in terms of memory overhead and execution speed.  The allocated blocks
     12  1.1       agc   cannot be freed individually, only all at once.  There can be multiple
     13  1.1       agc   allocators, though.
     14  1.1       agc */
     15  1.1       agc 
     16  1.1       agc #ifdef HAVE_CONFIG_H
     17  1.1       agc #include <config.h>
     18  1.1       agc #endif /* HAVE_CONFIG_H */
     19  1.1       agc #include <stdlib.h>
     20  1.1       agc #include <string.h>
     21  1.1       agc 
     22  1.1       agc #include "tre-internal.h"
     23  1.1       agc #include "tre-mem.h"
     24  1.1       agc #include "xmalloc.h"
     25  1.1       agc 
     26  1.1       agc 
     27  1.1       agc /* Returns a new memory allocator or NULL if out of memory. */
     28  1.1       agc tre_mem_t
     29  1.1       agc tre_mem_new_impl(int provided, void *provided_block)
     30  1.1       agc {
     31  1.1       agc   tre_mem_t mem;
     32  1.1       agc   if (provided)
     33  1.1       agc     {
     34  1.1       agc       mem = provided_block;
     35  1.1       agc       memset(mem, 0, sizeof(*mem));
     36  1.1       agc     }
     37  1.1       agc   else
     38  1.1       agc     mem = xcalloc(1, sizeof(*mem));
     39  1.1       agc   if (mem == NULL)
     40  1.1       agc     return NULL;
     41  1.1       agc   return mem;
     42  1.1       agc }
     43  1.1       agc 
     44  1.1       agc 
     45  1.1       agc /* Frees the memory allocator and all memory allocated with it. */
     46  1.1       agc void
     47  1.1       agc tre_mem_destroy(tre_mem_t mem)
     48  1.1       agc {
     49  1.1       agc   tre_list_t *tmp, *l = mem->blocks;
     50  1.1       agc 
     51  1.1       agc   while (l != NULL)
     52  1.1       agc     {
     53  1.1       agc       xfree(l->data);
     54  1.1       agc       tmp = l->next;
     55  1.1       agc       xfree(l);
     56  1.1       agc       l = tmp;
     57  1.1       agc     }
     58  1.1       agc   xfree(mem);
     59  1.1       agc }
     60  1.1       agc 
     61  1.1       agc 
     62  1.1       agc /* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
     63  1.1       agc    allocated block or NULL if an underlying malloc() failed. */
     64  1.1       agc void *
     65  1.1       agc tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
     66  1.1       agc 		   int zero, size_t size)
     67  1.1       agc {
     68  1.1       agc   void *ptr;
     69  1.1       agc 
     70  1.1       agc   if (mem->failed)
     71  1.1       agc     {
     72  1.1       agc       DPRINT(("tre_mem_alloc: oops, called after failure?!\n"));
     73  1.1       agc       return NULL;
     74  1.1       agc     }
     75  1.1       agc 
     76  1.1       agc #ifdef MALLOC_DEBUGGING
     77  1.1       agc   if (!provided)
     78  1.1       agc     {
     79  1.1       agc       ptr = xmalloc(1);
     80  1.1       agc       if (ptr == NULL)
     81  1.1       agc 	{
     82  1.1       agc 	  DPRINT(("tre_mem_alloc: xmalloc forced failure\n"));
     83  1.1       agc 	  mem->failed = 1;
     84  1.1       agc 	  return NULL;
     85  1.1       agc 	}
     86  1.1       agc       xfree(ptr);
     87  1.1       agc     }
     88  1.1       agc #endif /* MALLOC_DEBUGGING */
     89  1.1       agc 
     90  1.1       agc   if (mem->n < size)
     91  1.1       agc     {
     92  1.1       agc       /* We need more memory than is available in the current block.
     93  1.1       agc 	 Allocate a new block. */
     94  1.1       agc       tre_list_t *l;
     95  1.1       agc       if (provided)
     96  1.1       agc 	{
     97  1.1       agc 	  DPRINT(("tre_mem_alloc: using provided block\n"));
     98  1.1       agc 	  if (provided_block == NULL)
     99  1.1       agc 	    {
    100  1.1       agc 	      DPRINT(("tre_mem_alloc: provided block was NULL\n"));
    101  1.1       agc 	      mem->failed = 1;
    102  1.1       agc 	      return NULL;
    103  1.1       agc 	    }
    104  1.1       agc 	  mem->ptr = provided_block;
    105  1.1       agc 	  mem->n = TRE_MEM_BLOCK_SIZE;
    106  1.1       agc 	}
    107  1.1       agc       else
    108  1.1       agc 	{
    109  1.3  christos 	  size_t block_size;
    110  1.1       agc 	  if (size * 8 > TRE_MEM_BLOCK_SIZE)
    111  1.1       agc 	    block_size = size * 8;
    112  1.1       agc 	  else
    113  1.1       agc 	    block_size = TRE_MEM_BLOCK_SIZE;
    114  1.1       agc 	  DPRINT(("tre_mem_alloc: allocating new %d byte block\n",
    115  1.1       agc 		  block_size));
    116  1.1       agc 	  l = xmalloc(sizeof(*l));
    117  1.1       agc 	  if (l == NULL)
    118  1.1       agc 	    {
    119  1.1       agc 	      mem->failed = 1;
    120  1.1       agc 	      return NULL;
    121  1.1       agc 	    }
    122  1.1       agc 	  l->data = xmalloc(block_size);
    123  1.1       agc 	  if (l->data == NULL)
    124  1.1       agc 	    {
    125  1.1       agc 	      xfree(l);
    126  1.1       agc 	      mem->failed = 1;
    127  1.1       agc 	      return NULL;
    128  1.1       agc 	    }
    129  1.1       agc 	  l->next = NULL;
    130  1.1       agc 	  if (mem->current != NULL)
    131  1.1       agc 	    mem->current->next = l;
    132  1.1       agc 	  if (mem->blocks == NULL)
    133  1.1       agc 	    mem->blocks = l;
    134  1.1       agc 	  mem->current = l;
    135  1.1       agc 	  mem->ptr = l->data;
    136  1.1       agc 	  mem->n = block_size;
    137  1.1       agc 	}
    138  1.1       agc     }
    139  1.1       agc 
    140  1.1       agc   /* Make sure the next pointer will be aligned. */
    141  1.1       agc   size += ALIGN(mem->ptr + size, long);
    142  1.1       agc 
    143  1.1       agc   /* Allocate from current block. */
    144  1.1       agc   ptr = mem->ptr;
    145  1.1       agc   mem->ptr += size;
    146  1.1       agc   mem->n -= size;
    147  1.1       agc 
    148  1.1       agc   /* Set to zero if needed. */
    149  1.1       agc   if (zero)
    150  1.1       agc     memset(ptr, 0, size);
    151  1.1       agc 
    152  1.1       agc   return ptr;
    153  1.1       agc }
    154  1.1       agc 
    155  1.1       agc /* EOF */
    156