1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/*=============================================================================
29VideoCore 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
43extern "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
73typedef struct VCOS_BLOCKPOOL_HEADER_TAG
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 *next;
80 struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool;
81 } owner;
82} VCOS_BLOCKPOOL_HEADER_T;
83
84typedef 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
105typedef 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
163VCOSPRE_
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
170VCOSPRE_
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
177VCOSPRE_
178 VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
179 VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
180
181VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
182
183VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
184
185VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block);
186
187VCOSPRE_
188 VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count(
189 VCOS_BLOCKPOOL_T *pool);
190
191VCOSPRE_
192 VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count(
193 VCOS_BLOCKPOOL_T *pool);
194
195VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
196
197VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block);
198
199VCOSPRE_ void VCOSPOST_
200 *vcos_generic_blockpool_elem_from_handle(
201 VCOS_BLOCKPOOL_T *pool, uint32_t handle);
202
203VCOSPRE_ 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
208VCOS_INLINE_IMPL
209VCOS_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
218VCOS_INLINE_IMPL
219VCOS_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
227VCOS_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
234VCOS_INLINE_IMPL
235void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
236{
237 return vcos_generic_blockpool_alloc(pool);
238}
239
240VCOS_INLINE_IMPL
241void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
242{
243 return vcos_generic_blockpool_calloc(pool);
244}
245
246VCOS_INLINE_IMPL
247void vcos_blockpool_free(void *block)
248{
249 vcos_generic_blockpool_free(block);
250}
251
252VCOS_INLINE_IMPL
253VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
254{
255 return vcos_generic_blockpool_available_count(pool);
256}
257
258VCOS_INLINE_IMPL
259VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
260{
261 return vcos_generic_blockpool_used_count(pool);
262}
263
264VCOS_INLINE_IMPL
265void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
266{
267 vcos_generic_blockpool_delete(pool);
268}
269
270VCOS_INLINE_IMPL
271uint32_t vcos_blockpool_elem_to_handle(void *block)
272{
273 return vcos_generic_blockpool_elem_to_handle(block);
274}
275
276VCOS_INLINE_IMPL
277void *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
282VCOS_INLINE_IMPL
283uint32_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