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