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