xref: /netbsd-src/external/bsd/tre/dist/lib/tre-mem.c (revision f2a3d14797d93b3276c22bce2e57926bf739c955)
163d4abf0Sagc /*
263d4abf0Sagc   tre-mem.c - TRE memory allocator
363d4abf0Sagc 
463d4abf0Sagc   This software is released under a BSD-style license.
563d4abf0Sagc   See the file LICENSE for details and copyright.
663d4abf0Sagc 
763d4abf0Sagc */
863d4abf0Sagc 
963d4abf0Sagc /*
1063d4abf0Sagc   This memory allocator is for allocating small memory blocks efficiently
1163d4abf0Sagc   in terms of memory overhead and execution speed.  The allocated blocks
1263d4abf0Sagc   cannot be freed individually, only all at once.  There can be multiple
1363d4abf0Sagc   allocators, though.
1463d4abf0Sagc */
1563d4abf0Sagc 
1663d4abf0Sagc #ifdef HAVE_CONFIG_H
1763d4abf0Sagc #include <config.h>
1863d4abf0Sagc #endif /* HAVE_CONFIG_H */
1963d4abf0Sagc #include <stdlib.h>
2063d4abf0Sagc #include <string.h>
2163d4abf0Sagc 
2263d4abf0Sagc #include "tre-internal.h"
2363d4abf0Sagc #include "tre-mem.h"
2463d4abf0Sagc #include "xmalloc.h"
2563d4abf0Sagc 
2663d4abf0Sagc 
2763d4abf0Sagc /* Returns a new memory allocator or NULL if out of memory. */
2863d4abf0Sagc tre_mem_t
tre_mem_new_impl(int provided,void * provided_block)2963d4abf0Sagc tre_mem_new_impl(int provided, void *provided_block)
3063d4abf0Sagc {
3163d4abf0Sagc   tre_mem_t mem;
3263d4abf0Sagc   if (provided)
3363d4abf0Sagc     {
3463d4abf0Sagc       mem = provided_block;
3563d4abf0Sagc       memset(mem, 0, sizeof(*mem));
3663d4abf0Sagc     }
3763d4abf0Sagc   else
3863d4abf0Sagc     mem = xcalloc(1, sizeof(*mem));
3963d4abf0Sagc   if (mem == NULL)
4063d4abf0Sagc     return NULL;
4163d4abf0Sagc   return mem;
4263d4abf0Sagc }
4363d4abf0Sagc 
4463d4abf0Sagc 
4563d4abf0Sagc /* Frees the memory allocator and all memory allocated with it. */
4663d4abf0Sagc void
tre_mem_destroy(tre_mem_t mem)4763d4abf0Sagc tre_mem_destroy(tre_mem_t mem)
4863d4abf0Sagc {
4963d4abf0Sagc   tre_list_t *tmp, *l = mem->blocks;
5063d4abf0Sagc 
5163d4abf0Sagc   while (l != NULL)
5263d4abf0Sagc     {
5363d4abf0Sagc       xfree(l->data);
5463d4abf0Sagc       tmp = l->next;
5563d4abf0Sagc       xfree(l);
5663d4abf0Sagc       l = tmp;
5763d4abf0Sagc     }
5863d4abf0Sagc   xfree(mem);
5963d4abf0Sagc }
6063d4abf0Sagc 
6163d4abf0Sagc 
6263d4abf0Sagc /* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
6363d4abf0Sagc    allocated block or NULL if an underlying malloc() failed. */
6463d4abf0Sagc void *
tre_mem_alloc_impl(tre_mem_t mem,int provided,void * provided_block,int zero,size_t size)6563d4abf0Sagc tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
6663d4abf0Sagc 		   int zero, size_t size)
6763d4abf0Sagc {
6863d4abf0Sagc   void *ptr;
6963d4abf0Sagc 
7063d4abf0Sagc   if (mem->failed)
7163d4abf0Sagc     {
7263d4abf0Sagc       DPRINT(("tre_mem_alloc: oops, called after failure?!\n"));
7363d4abf0Sagc       return NULL;
7463d4abf0Sagc     }
7563d4abf0Sagc 
7663d4abf0Sagc #ifdef MALLOC_DEBUGGING
7763d4abf0Sagc   if (!provided)
7863d4abf0Sagc     {
7963d4abf0Sagc       ptr = xmalloc(1);
8063d4abf0Sagc       if (ptr == NULL)
8163d4abf0Sagc 	{
8263d4abf0Sagc 	  DPRINT(("tre_mem_alloc: xmalloc forced failure\n"));
8363d4abf0Sagc 	  mem->failed = 1;
8463d4abf0Sagc 	  return NULL;
8563d4abf0Sagc 	}
8663d4abf0Sagc       xfree(ptr);
8763d4abf0Sagc     }
8863d4abf0Sagc #endif /* MALLOC_DEBUGGING */
8963d4abf0Sagc 
9063d4abf0Sagc   if (mem->n < size)
9163d4abf0Sagc     {
9263d4abf0Sagc       /* We need more memory than is available in the current block.
9363d4abf0Sagc 	 Allocate a new block. */
9463d4abf0Sagc       tre_list_t *l;
9563d4abf0Sagc       if (provided)
9663d4abf0Sagc 	{
9763d4abf0Sagc 	  DPRINT(("tre_mem_alloc: using provided block\n"));
9863d4abf0Sagc 	  if (provided_block == NULL)
9963d4abf0Sagc 	    {
10063d4abf0Sagc 	      DPRINT(("tre_mem_alloc: provided block was NULL\n"));
10163d4abf0Sagc 	      mem->failed = 1;
10263d4abf0Sagc 	      return NULL;
10363d4abf0Sagc 	    }
10463d4abf0Sagc 	  mem->ptr = provided_block;
10563d4abf0Sagc 	  mem->n = TRE_MEM_BLOCK_SIZE;
10663d4abf0Sagc 	}
10763d4abf0Sagc       else
10863d4abf0Sagc 	{
109*f2a3d147Schristos 	  size_t block_size;
11063d4abf0Sagc 	  if (size * 8 > TRE_MEM_BLOCK_SIZE)
11163d4abf0Sagc 	    block_size = size * 8;
11263d4abf0Sagc 	  else
11363d4abf0Sagc 	    block_size = TRE_MEM_BLOCK_SIZE;
11463d4abf0Sagc 	  DPRINT(("tre_mem_alloc: allocating new %d byte block\n",
11563d4abf0Sagc 		  block_size));
11663d4abf0Sagc 	  l = xmalloc(sizeof(*l));
11763d4abf0Sagc 	  if (l == NULL)
11863d4abf0Sagc 	    {
11963d4abf0Sagc 	      mem->failed = 1;
12063d4abf0Sagc 	      return NULL;
12163d4abf0Sagc 	    }
12263d4abf0Sagc 	  l->data = xmalloc(block_size);
12363d4abf0Sagc 	  if (l->data == NULL)
12463d4abf0Sagc 	    {
12563d4abf0Sagc 	      xfree(l);
12663d4abf0Sagc 	      mem->failed = 1;
12763d4abf0Sagc 	      return NULL;
12863d4abf0Sagc 	    }
12963d4abf0Sagc 	  l->next = NULL;
13063d4abf0Sagc 	  if (mem->current != NULL)
13163d4abf0Sagc 	    mem->current->next = l;
13263d4abf0Sagc 	  if (mem->blocks == NULL)
13363d4abf0Sagc 	    mem->blocks = l;
13463d4abf0Sagc 	  mem->current = l;
13563d4abf0Sagc 	  mem->ptr = l->data;
13663d4abf0Sagc 	  mem->n = block_size;
13763d4abf0Sagc 	}
13863d4abf0Sagc     }
13963d4abf0Sagc 
14063d4abf0Sagc   /* Make sure the next pointer will be aligned. */
14163d4abf0Sagc   size += ALIGN(mem->ptr + size, long);
14263d4abf0Sagc 
14363d4abf0Sagc   /* Allocate from current block. */
14463d4abf0Sagc   ptr = mem->ptr;
14563d4abf0Sagc   mem->ptr += size;
14663d4abf0Sagc   mem->n -= size;
14763d4abf0Sagc 
14863d4abf0Sagc   /* Set to zero if needed. */
14963d4abf0Sagc   if (zero)
15063d4abf0Sagc     memset(ptr, 0, size);
15163d4abf0Sagc 
15263d4abf0Sagc   return ptr;
15363d4abf0Sagc }
15463d4abf0Sagc 
15563d4abf0Sagc /* EOF */
156