1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | /*============================================================================= |
29 | VideoCore OS Abstraction Layer - event flags implemented via a semaphore |
30 | =============================================================================*/ |
31 | |
32 | #ifndef VCOS_GENERIC_BLOCKPOOL_H |
33 | #define VCOS_GENERIC_BLOCKPOOL_H |
34 | |
35 | /** |
36 | * \file |
37 | * |
38 | * This provides a generic, thread safe implementation of a VCOS block pool |
39 | * fixed size memory allocator. |
40 | */ |
41 | |
42 | #ifdef __cplusplus |
43 | extern "C" { |
44 | #endif |
45 | |
46 | #include "interface/vcos/vcos_types.h" |
47 | |
48 | /** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the |
49 | * subpool id. */ |
50 | #define VCOS_BLOCKPOOL_SUBPOOL_BITS 3 |
51 | #define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) |
52 | |
53 | /* Make zero an invalid handle at the cost of decreasing the maximum |
54 | * number of blocks (2^28) by 1. Alternatively, a spare bit could be |
55 | * used to indicated valid blocks but there are likely to be better |
56 | * uses for spare bits. e.g. allowing more subpools |
57 | */ |
58 | #define INDEX_OFFSET 1 |
59 | |
60 | #define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \ |
61 | (((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET) |
62 | |
63 | #define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \ |
64 | ((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1)) |
65 | |
66 | #define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \ |
67 | ((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s)) |
68 | |
69 | #define VCOS_BLOCKPOOL_INVALID_HANDLE 0 |
70 | #define VCOS_BLOCKPOOL_ALIGN_DEFAULT sizeof(unsigned long) |
71 | #define VCOS_BLOCKPOOL_FLAG_NONE 0 |
72 | |
73 | typedef struct |
74 | { |
75 | /* Blocks either refer to to the pool if they are allocated |
76 | * or the free list if they are available. |
77 | */ |
78 | union { |
79 | struct VCOS_BLOCKPOOL_HEADER_TAG *; |
80 | struct VCOS_BLOCKPOOL_SUBPOOL_TAG* ; |
81 | } ; |
82 | } ; |
83 | |
84 | typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG |
85 | { |
86 | /** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */ |
87 | uint32_t magic; |
88 | VCOS_BLOCKPOOL_HEADER_T* free_list; |
89 | /* The start of the pool memory */ |
90 | void *mem; |
91 | /* Address of the first block header */ |
92 | void *start; |
93 | /* The end of the subpool */ |
94 | void *end; |
95 | /** The number of blocks in this sub-pool */ |
96 | VCOS_UNSIGNED num_blocks; |
97 | /** Current number of available blocks in this sub-pool */ |
98 | VCOS_UNSIGNED available_blocks; |
99 | /** Pointers to the pool that owns this sub-pool */ |
100 | struct VCOS_BLOCKPOOL_TAG* owner; |
101 | /** Define properties such as memory ownership */ |
102 | uint32_t flags; |
103 | } VCOS_BLOCKPOOL_SUBPOOL_T; |
104 | |
105 | typedef struct VCOS_BLOCKPOOL_TAG |
106 | { |
107 | /** VCOS_BLOCKPOOL_MAGIC */ |
108 | uint32_t magic; |
109 | /** Thread safety for Alloc, Free, Delete, Stats */ |
110 | VCOS_MUTEX_T mutex; |
111 | /** Alignment of block data pointers */ |
112 | VCOS_UNSIGNED align; |
113 | /** Flags for future use e.g. cache options */ |
114 | VCOS_UNSIGNED flags; |
115 | /** The size of the block data */ |
116 | size_t block_data_size; |
117 | /** Block size inc overheads */ |
118 | size_t block_size; |
119 | /** Name for debugging */ |
120 | const char *name; |
121 | /* The number of subpools that may be used */ |
122 | VCOS_UNSIGNED num_subpools; |
123 | /** Number of blocks in each dynamically allocated subpool */ |
124 | VCOS_UNSIGNED num_extension_blocks; |
125 | /** Array of subpools. Subpool zero is is not deleted until the pool is |
126 | * destroed. If the index of the pool is < num_subpools and |
127 | * subpool[index.mem] is null then the subpool entry is valid but |
128 | * "not currently allocated" */ |
129 | VCOS_BLOCKPOOL_SUBPOOL_T subpools[VCOS_BLOCKPOOL_MAX_SUBPOOLS]; |
130 | } VCOS_BLOCKPOOL_T; |
131 | |
132 | #define VCOS_BLOCKPOOL_ROUND_UP(x,s) (((x) + ((s) - 1)) & ~((s) - 1)) |
133 | /** |
134 | * Calculates the size in bytes required for a block pool containing |
135 | * num_blocks of size block_size plus any overheads. |
136 | * |
137 | * The block pool header (VCOS_BLOCKPOOL_T) is allocated separately |
138 | * |
139 | * Overheads: |
140 | * block_size + header must be rounded up to meet the required alignment |
141 | * The start of the first block may need to be up to align bytes |
142 | * into the given buffer because statically allocated buffers within structures |
143 | * are not guaranteed to be aligned as required. |
144 | */ |
145 | #define VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align) \ |
146 | ((VCOS_BLOCKPOOL_ROUND_UP((block_size) + (align >= 4096 ? 32 : 0) + sizeof(VCOS_BLOCKPOOL_HEADER_T), \ |
147 | (align)) * (num_blocks)) + (align)) |
148 | |
149 | /** |
150 | * Sanity check to verify whether a handle is potentially a blockpool handle |
151 | * when the pool pointer is not available. |
152 | * |
153 | * If the pool pointer is available use vcos_blockpool_elem_to_handle instead. |
154 | * |
155 | * @param handle the handle to verify |
156 | * @param max_blocks the expected maximum number of block in the pool |
157 | * that the handle belongs to. |
158 | */ |
159 | #define VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(handle, max_blocks) \ |
160 | ((handle) != VCOS_BLOCKPOOL_INVALID_HANDLE \ |
161 | && VCOS_BLOCKPOOL_HANDLE_GET_INDEX((handle)) < (max_blocks)) |
162 | |
163 | VCOSPRE_ |
164 | VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool, |
165 | VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, |
166 | void *start, VCOS_UNSIGNED pool_size, |
167 | VCOS_UNSIGNED align, VCOS_UNSIGNED flags, |
168 | const char *name); |
169 | |
170 | VCOSPRE_ |
171 | VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_create_on_heap( |
172 | VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks, |
173 | VCOS_UNSIGNED block_size, |
174 | VCOS_UNSIGNED align, VCOS_UNSIGNED flags, |
175 | const char *name); |
176 | |
177 | VCOSPRE_ |
178 | VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool, |
179 | VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks); |
180 | |
181 | VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool); |
182 | |
183 | VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool); |
184 | |
185 | VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block); |
186 | |
187 | VCOSPRE_ |
188 | VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count( |
189 | VCOS_BLOCKPOOL_T *pool); |
190 | |
191 | VCOSPRE_ |
192 | VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count( |
193 | VCOS_BLOCKPOOL_T *pool); |
194 | |
195 | VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool); |
196 | |
197 | VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block); |
198 | |
199 | VCOSPRE_ void VCOSPOST_ |
200 | *vcos_generic_blockpool_elem_from_handle( |
201 | VCOS_BLOCKPOOL_T *pool, uint32_t handle); |
202 | |
203 | VCOSPRE_ uint32_t VCOSPOST_ |
204 | vcos_generic_blockpool_is_valid_elem( |
205 | VCOS_BLOCKPOOL_T *pool, const void *block); |
206 | #if defined(VCOS_INLINE_BODIES) |
207 | |
208 | VCOS_INLINE_IMPL |
209 | VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool, |
210 | VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, |
211 | void *start, VCOS_UNSIGNED pool_size, |
212 | VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name) |
213 | { |
214 | return vcos_generic_blockpool_init(pool, num_blocks, block_size, |
215 | start, pool_size, align, flags, name); |
216 | } |
217 | |
218 | VCOS_INLINE_IMPL |
219 | VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool, |
220 | VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, |
221 | VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name) |
222 | { |
223 | return vcos_generic_blockpool_create_on_heap( |
224 | pool, num_blocks, block_size, align, flags, name); |
225 | } |
226 | |
227 | VCOS_INLINE_IMPL |
228 | VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool, |
229 | VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks) |
230 | { |
231 | return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks); |
232 | } |
233 | |
234 | VCOS_INLINE_IMPL |
235 | void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool) |
236 | { |
237 | return vcos_generic_blockpool_alloc(pool); |
238 | } |
239 | |
240 | VCOS_INLINE_IMPL |
241 | void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool) |
242 | { |
243 | return vcos_generic_blockpool_calloc(pool); |
244 | } |
245 | |
246 | VCOS_INLINE_IMPL |
247 | void vcos_blockpool_free(void *block) |
248 | { |
249 | vcos_generic_blockpool_free(block); |
250 | } |
251 | |
252 | VCOS_INLINE_IMPL |
253 | VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool) |
254 | { |
255 | return vcos_generic_blockpool_available_count(pool); |
256 | } |
257 | |
258 | VCOS_INLINE_IMPL |
259 | VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool) |
260 | { |
261 | return vcos_generic_blockpool_used_count(pool); |
262 | } |
263 | |
264 | VCOS_INLINE_IMPL |
265 | void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool) |
266 | { |
267 | vcos_generic_blockpool_delete(pool); |
268 | } |
269 | |
270 | VCOS_INLINE_IMPL |
271 | uint32_t vcos_blockpool_elem_to_handle(void *block) |
272 | { |
273 | return vcos_generic_blockpool_elem_to_handle(block); |
274 | } |
275 | |
276 | VCOS_INLINE_IMPL |
277 | void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle) |
278 | { |
279 | return vcos_generic_blockpool_elem_from_handle(pool, handle); |
280 | } |
281 | |
282 | VCOS_INLINE_IMPL |
283 | uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block) |
284 | { |
285 | return vcos_generic_blockpool_is_valid_elem(pool, block); |
286 | } |
287 | #endif /* VCOS_INLINE_BODIES */ |
288 | |
289 | |
290 | #ifdef __cplusplus |
291 | } |
292 | #endif |
293 | #endif /* VCOS_GENERIC_BLOCKPOOL_H */ |
294 | |
295 | |