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