1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #ifndef OBJECT_POOL_H 8*91f16700Schasinglulu #define OBJECT_POOL_H 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <stdlib.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <common/debug.h> 13*91f16700Schasinglulu #include <lib/utils_def.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu /* 16*91f16700Schasinglulu * Pool of statically allocated objects. 17*91f16700Schasinglulu * 18*91f16700Schasinglulu * Objects can be reserved but not freed. This is by design and it is not a 19*91f16700Schasinglulu * limitation. We do not want to introduce complexity induced by memory freeing, 20*91f16700Schasinglulu * such as use-after-free bugs, memory fragmentation and so on. 21*91f16700Schasinglulu * 22*91f16700Schasinglulu * The object size and capacity of the pool are fixed at build time. So is the 23*91f16700Schasinglulu * address of the objects back store. 24*91f16700Schasinglulu */ 25*91f16700Schasinglulu struct object_pool { 26*91f16700Schasinglulu /* Size of 1 object in the pool in byte unit. */ 27*91f16700Schasinglulu const size_t obj_size; 28*91f16700Schasinglulu 29*91f16700Schasinglulu /* Number of objects in the pool. */ 30*91f16700Schasinglulu const size_t capacity; 31*91f16700Schasinglulu 32*91f16700Schasinglulu /* Objects back store. */ 33*91f16700Schasinglulu void *const objects; 34*91f16700Schasinglulu 35*91f16700Schasinglulu /* How many objects are currently allocated. */ 36*91f16700Schasinglulu size_t used; 37*91f16700Schasinglulu }; 38*91f16700Schasinglulu 39*91f16700Schasinglulu /* Create a static pool of objects. */ 40*91f16700Schasinglulu #define OBJECT_POOL(_pool_name, _obj_backstore, _obj_size, _obj_count) \ 41*91f16700Schasinglulu struct object_pool _pool_name = { \ 42*91f16700Schasinglulu .objects = (_obj_backstore), \ 43*91f16700Schasinglulu .obj_size = (_obj_size), \ 44*91f16700Schasinglulu .capacity = (_obj_count), \ 45*91f16700Schasinglulu .used = 0U, \ 46*91f16700Schasinglulu } 47*91f16700Schasinglulu 48*91f16700Schasinglulu /* Create a static pool of objects out of an array of pre-allocated objects. */ 49*91f16700Schasinglulu #define OBJECT_POOL_ARRAY(_pool_name, _obj_array) \ 50*91f16700Schasinglulu OBJECT_POOL(_pool_name, (_obj_array), \ 51*91f16700Schasinglulu sizeof((_obj_array)[0]), ARRAY_SIZE(_obj_array)) 52*91f16700Schasinglulu 53*91f16700Schasinglulu /* 54*91f16700Schasinglulu * Allocate 'count' objects from a pool. 55*91f16700Schasinglulu * Return the address of the first object. Panic on error. 56*91f16700Schasinglulu */ 57*91f16700Schasinglulu static inline void *pool_alloc_n(struct object_pool *pool, size_t count) 58*91f16700Schasinglulu { 59*91f16700Schasinglulu if ((pool->used + count) > pool->capacity) { 60*91f16700Schasinglulu ERROR("Cannot allocate %zu objects out of pool (%zu objects left).\n", 61*91f16700Schasinglulu count, pool->capacity - pool->used); 62*91f16700Schasinglulu panic(); 63*91f16700Schasinglulu } 64*91f16700Schasinglulu 65*91f16700Schasinglulu void *obj = (char *)(pool->objects) + (pool->obj_size * pool->used); 66*91f16700Schasinglulu pool->used += count; 67*91f16700Schasinglulu return obj; 68*91f16700Schasinglulu } 69*91f16700Schasinglulu 70*91f16700Schasinglulu /* 71*91f16700Schasinglulu * Allocate 1 object from a pool. 72*91f16700Schasinglulu * Return the address of the object. Panic on error. 73*91f16700Schasinglulu */ 74*91f16700Schasinglulu static inline void *pool_alloc(struct object_pool *pool) 75*91f16700Schasinglulu { 76*91f16700Schasinglulu return pool_alloc_n(pool, 1U); 77*91f16700Schasinglulu } 78*91f16700Schasinglulu 79*91f16700Schasinglulu #endif /* OBJECT_POOL_H */ 80