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