1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci tre-mem.c - TRE memory allocator 3570af302Sopenharmony_ci 4570af302Sopenharmony_ci Copyright (c) 2001-2009 Ville Laurikari <vl@iki.fi> 5570af302Sopenharmony_ci All rights reserved. 6570af302Sopenharmony_ci 7570af302Sopenharmony_ci Redistribution and use in source and binary forms, with or without 8570af302Sopenharmony_ci modification, are permitted provided that the following conditions 9570af302Sopenharmony_ci are met: 10570af302Sopenharmony_ci 11570af302Sopenharmony_ci 1. Redistributions of source code must retain the above copyright 12570af302Sopenharmony_ci notice, this list of conditions and the following disclaimer. 13570af302Sopenharmony_ci 14570af302Sopenharmony_ci 2. Redistributions in binary form must reproduce the above copyright 15570af302Sopenharmony_ci notice, this list of conditions and the following disclaimer in the 16570af302Sopenharmony_ci documentation and/or other materials provided with the distribution. 17570af302Sopenharmony_ci 18570af302Sopenharmony_ci THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS 19570af302Sopenharmony_ci ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20570af302Sopenharmony_ci LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21570af302Sopenharmony_ci A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22570af302Sopenharmony_ci HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23570af302Sopenharmony_ci SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24570af302Sopenharmony_ci LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25570af302Sopenharmony_ci DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26570af302Sopenharmony_ci THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27570af302Sopenharmony_ci (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28570af302Sopenharmony_ci OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29570af302Sopenharmony_ci 30570af302Sopenharmony_ci*/ 31570af302Sopenharmony_ci 32570af302Sopenharmony_ci/* 33570af302Sopenharmony_ci This memory allocator is for allocating small memory blocks efficiently 34570af302Sopenharmony_ci in terms of memory overhead and execution speed. The allocated blocks 35570af302Sopenharmony_ci cannot be freed individually, only all at once. There can be multiple 36570af302Sopenharmony_ci allocators, though. 37570af302Sopenharmony_ci*/ 38570af302Sopenharmony_ci 39570af302Sopenharmony_ci#include <stdlib.h> 40570af302Sopenharmony_ci#include <string.h> 41570af302Sopenharmony_ci 42570af302Sopenharmony_ci#include "tre.h" 43570af302Sopenharmony_ci 44570af302Sopenharmony_ci/* 45570af302Sopenharmony_ci This memory allocator is for allocating small memory blocks efficiently 46570af302Sopenharmony_ci in terms of memory overhead and execution speed. The allocated blocks 47570af302Sopenharmony_ci cannot be freed individually, only all at once. There can be multiple 48570af302Sopenharmony_ci allocators, though. 49570af302Sopenharmony_ci*/ 50570af302Sopenharmony_ci 51570af302Sopenharmony_ci/* Returns a new memory allocator or NULL if out of memory. */ 52570af302Sopenharmony_citre_mem_t 53570af302Sopenharmony_citre_mem_new_impl(int provided, void *provided_block) 54570af302Sopenharmony_ci{ 55570af302Sopenharmony_ci tre_mem_t mem; 56570af302Sopenharmony_ci if (provided) 57570af302Sopenharmony_ci { 58570af302Sopenharmony_ci mem = provided_block; 59570af302Sopenharmony_ci memset(mem, 0, sizeof(*mem)); 60570af302Sopenharmony_ci } 61570af302Sopenharmony_ci else 62570af302Sopenharmony_ci mem = xcalloc(1, sizeof(*mem)); 63570af302Sopenharmony_ci if (mem == NULL) 64570af302Sopenharmony_ci return NULL; 65570af302Sopenharmony_ci return mem; 66570af302Sopenharmony_ci} 67570af302Sopenharmony_ci 68570af302Sopenharmony_ci 69570af302Sopenharmony_ci/* Frees the memory allocator and all memory allocated with it. */ 70570af302Sopenharmony_civoid 71570af302Sopenharmony_citre_mem_destroy(tre_mem_t mem) 72570af302Sopenharmony_ci{ 73570af302Sopenharmony_ci tre_list_t *tmp, *l = mem->blocks; 74570af302Sopenharmony_ci 75570af302Sopenharmony_ci while (l != NULL) 76570af302Sopenharmony_ci { 77570af302Sopenharmony_ci xfree(l->data); 78570af302Sopenharmony_ci tmp = l->next; 79570af302Sopenharmony_ci xfree(l); 80570af302Sopenharmony_ci l = tmp; 81570af302Sopenharmony_ci } 82570af302Sopenharmony_ci xfree(mem); 83570af302Sopenharmony_ci} 84570af302Sopenharmony_ci 85570af302Sopenharmony_ci 86570af302Sopenharmony_ci/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the 87570af302Sopenharmony_ci allocated block or NULL if an underlying malloc() failed. */ 88570af302Sopenharmony_civoid * 89570af302Sopenharmony_citre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, 90570af302Sopenharmony_ci int zero, size_t size) 91570af302Sopenharmony_ci{ 92570af302Sopenharmony_ci void *ptr; 93570af302Sopenharmony_ci 94570af302Sopenharmony_ci if (mem->failed) 95570af302Sopenharmony_ci { 96570af302Sopenharmony_ci return NULL; 97570af302Sopenharmony_ci } 98570af302Sopenharmony_ci 99570af302Sopenharmony_ci if (mem->n < size) 100570af302Sopenharmony_ci { 101570af302Sopenharmony_ci /* We need more memory than is available in the current block. 102570af302Sopenharmony_ci Allocate a new block. */ 103570af302Sopenharmony_ci tre_list_t *l; 104570af302Sopenharmony_ci if (provided) 105570af302Sopenharmony_ci { 106570af302Sopenharmony_ci if (provided_block == NULL) 107570af302Sopenharmony_ci { 108570af302Sopenharmony_ci mem->failed = 1; 109570af302Sopenharmony_ci return NULL; 110570af302Sopenharmony_ci } 111570af302Sopenharmony_ci mem->ptr = provided_block; 112570af302Sopenharmony_ci mem->n = TRE_MEM_BLOCK_SIZE; 113570af302Sopenharmony_ci } 114570af302Sopenharmony_ci else 115570af302Sopenharmony_ci { 116570af302Sopenharmony_ci int block_size; 117570af302Sopenharmony_ci if (size * 8 > TRE_MEM_BLOCK_SIZE) 118570af302Sopenharmony_ci block_size = size * 8; 119570af302Sopenharmony_ci else 120570af302Sopenharmony_ci block_size = TRE_MEM_BLOCK_SIZE; 121570af302Sopenharmony_ci l = xmalloc(sizeof(*l)); 122570af302Sopenharmony_ci if (l == NULL) 123570af302Sopenharmony_ci { 124570af302Sopenharmony_ci mem->failed = 1; 125570af302Sopenharmony_ci return NULL; 126570af302Sopenharmony_ci } 127570af302Sopenharmony_ci l->data = xmalloc(block_size); 128570af302Sopenharmony_ci if (l->data == NULL) 129570af302Sopenharmony_ci { 130570af302Sopenharmony_ci xfree(l); 131570af302Sopenharmony_ci mem->failed = 1; 132570af302Sopenharmony_ci return NULL; 133570af302Sopenharmony_ci } 134570af302Sopenharmony_ci l->next = NULL; 135570af302Sopenharmony_ci if (mem->current != NULL) 136570af302Sopenharmony_ci mem->current->next = l; 137570af302Sopenharmony_ci if (mem->blocks == NULL) 138570af302Sopenharmony_ci mem->blocks = l; 139570af302Sopenharmony_ci mem->current = l; 140570af302Sopenharmony_ci mem->ptr = l->data; 141570af302Sopenharmony_ci mem->n = block_size; 142570af302Sopenharmony_ci } 143570af302Sopenharmony_ci } 144570af302Sopenharmony_ci 145570af302Sopenharmony_ci /* Make sure the next pointer will be aligned. */ 146570af302Sopenharmony_ci size += ALIGN(mem->ptr + size, long); 147570af302Sopenharmony_ci 148570af302Sopenharmony_ci /* Allocate from current block. */ 149570af302Sopenharmony_ci ptr = mem->ptr; 150570af302Sopenharmony_ci mem->ptr += size; 151570af302Sopenharmony_ci mem->n -= size; 152570af302Sopenharmony_ci 153570af302Sopenharmony_ci /* Set to zero if needed. */ 154570af302Sopenharmony_ci if (zero) 155570af302Sopenharmony_ci memset(ptr, 0, size); 156570af302Sopenharmony_ci 157570af302Sopenharmony_ci return ptr; 158570af302Sopenharmony_ci} 159