Line data Source code
1 : /* 2 : * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 : * 4 : * Redistribution and use in source and binary forms, with or without 5 : * modification, are permitted provided that the following conditions 6 : * are met: 7 : * 8 : * 1. Redistributions of source code must retain the above copyright 9 : * notice, this list of conditions and the following disclaimer. 10 : * 11 : * 2. Redistributions in binary form must reproduce the above copyright 12 : * notice, this list of conditions and the following disclaimer in the 13 : * documentation and/or other materials provided with the distribution. 14 : * 15 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 : * POSSIBILITY OF SUCH DAMAGE. 26 : */ 27 : 28 : #include "tommyalloc.h" 29 : 30 : /******************************************************************************/ 31 : /* allocator */ 32 : 33 : /** 34 : * Basic allocation segment. 35 : * Smaller of a memory page, to allow also a little heap overread. 36 : * The heap manager may put it in a single memory page. 37 : */ 38 : #define TOMMY_ALLOCATOR_BLOCK_SIZE (4096 - 64) 39 : 40 5 : TOMMY_API void tommy_allocator_init(tommy_allocator* alloc, tommy_size_t block_size, tommy_size_t align_size) 41 : { 42 : /* setup the minimal alignment */ 43 5 : if (align_size < sizeof(void*)) 44 1 : align_size = sizeof(void*); 45 : 46 : /* ensure that the block_size keeps the alignment */ 47 5 : if (block_size % align_size != 0) 48 1 : block_size += align_size - block_size % align_size; 49 : 50 5 : alloc->block_size = block_size; 51 5 : alloc->align_size = align_size; 52 : 53 5 : alloc->count = 0; 54 5 : alloc->free_block = 0; 55 5 : alloc->used_segment = 0; 56 5 : } 57 : 58 : /** 59 : * Reset the allocator and free all. 60 : */ 61 5 : static void allocator_reset(tommy_allocator* alloc) 62 : { 63 5 : tommy_allocator_entry* block = alloc->used_segment; 64 : 65 170514 : while (block) { 66 170509 : tommy_allocator_entry* block_next = block->next; 67 170509 : tommy_free(block); 68 170509 : block = block_next; 69 : } 70 : 71 5 : alloc->count = 0; 72 5 : alloc->free_block = 0; 73 5 : alloc->used_segment = 0; 74 5 : } 75 : 76 5 : TOMMY_API void tommy_allocator_done(tommy_allocator* alloc) 77 : { 78 5 : allocator_reset(alloc); 79 5 : } 80 : 81 10571435 : TOMMY_API void* tommy_allocator_alloc(tommy_allocator* alloc) 82 : { 83 : void* ptr; 84 : 85 : /* if no free block available */ 86 10571435 : if (!alloc->free_block) { 87 : tommy_uintptr_t off, mis; 88 : tommy_size_t size; 89 : char* data; 90 : tommy_allocator_entry* segment; 91 : 92 : /* default allocation size */ 93 170509 : size = TOMMY_ALLOCATOR_BLOCK_SIZE; 94 : 95 : /* ensure that we can allocate at least one block */ 96 170509 : if (size < sizeof(tommy_allocator_entry) + alloc->align_size + alloc->block_size) 97 1 : size = sizeof(tommy_allocator_entry) + alloc->align_size + alloc->block_size; 98 : 99 170509 : data = tommy_cast(char*, tommy_malloc(size)); 100 170509 : segment = (tommy_allocator_entry*)data; 101 : 102 : /* put in the segment list */ 103 170509 : segment->next = alloc->used_segment; 104 170509 : alloc->used_segment = segment; 105 170509 : data += sizeof(tommy_allocator_entry); 106 : 107 : /* align if not aligned */ 108 170509 : off = (tommy_uintptr_t)data; 109 170509 : mis = off % alloc->align_size; 110 170509 : if (mis != 0) { 111 170509 : data += alloc->align_size - mis; 112 170509 : size -= alloc->align_size - mis; 113 : } 114 : 115 : /* insert in free list */ 116 : do { 117 10571497 : tommy_allocator_entry* free_block = (tommy_allocator_entry*)data; 118 10571497 : free_block->next = alloc->free_block; 119 10571497 : alloc->free_block = free_block; 120 : 121 10571497 : data += alloc->block_size; 122 10571497 : size -= alloc->block_size; 123 10571497 : } while (size >= alloc->block_size); 124 : } 125 : 126 : /* remove one from the free list */ 127 10571435 : ptr = alloc->free_block; 128 10571435 : alloc->free_block = alloc->free_block->next; 129 : 130 10571435 : ++alloc->count; 131 : 132 10571435 : return ptr; 133 : } 134 : 135 10571434 : TOMMY_API void tommy_allocator_free(tommy_allocator* alloc, void* ptr) 136 : { 137 10571434 : tommy_allocator_entry* free_block = tommy_cast(tommy_allocator_entry*, ptr); 138 : 139 : /* put it in the free list */ 140 10571434 : free_block->next = alloc->free_block; 141 10571434 : alloc->free_block = free_block; 142 : 143 10571434 : --alloc->count; 144 10571434 : } 145 : 146 1 : TOMMY_API tommy_size_t tommy_allocator_memory_usage(tommy_allocator* alloc) 147 : { 148 1 : return alloc->count * (tommy_size_t)alloc->block_size; 149 : } 150 :