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 : 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 170519 : 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 : void tommy_allocator_done(tommy_allocator* alloc)
77 : {
78 5 : allocator_reset(alloc);
79 5 : }
80 :
81 10571435 : 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 : 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_size_t tommy_allocator_memory_usage(tommy_allocator* alloc)
147 : {
148 1 : return alloc->count * (tommy_size_t)alloc->block_size;
149 : }
150 :
|