| 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 | |