Introduce object pool allocator
authorSandrine Bailleux <sandrine.bailleux@arm.com>
Fri, 1 Jun 2018 12:17:08 +0000 (14:17 +0200)
committerSandrine Bailleux <sandrine.bailleux@arm.com>
Thu, 11 Oct 2018 14:11:18 +0000 (16:11 +0200)
The object pool allocator provides a simplistic interface to manage
allocation in a fixed-size static array. The caller creates a static
"object pool" out of such an array and may then call pool_alloc() to
get the next available object within the pool. There is also a variant
to get multiple consecutive objects: pool_alloc_n().

Note that this interface does not provide any way to free the objects
afterwards. This is by design and it is not a limitation. We do not
want to introduce complexity induced by memory freeing, such as
use-after-free bugs, memory fragmentation and so on.

Change-Id: Iefc2e153767851fbde5841a295f92ae48adda71f
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
include/lib/object_pool.h [new file with mode: 0644]

diff --git a/include/lib/object_pool.h b/include/lib/object_pool.h
new file mode 100644 (file)
index 0000000..7d40b41
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OBJECT_POOL_H
+#define OBJECT_POOL_H
+
+#include <debug.h>
+#include <stdlib.h>
+#include <utils_def.h>
+
+/*
+ * Pool of statically allocated objects.
+ *
+ * Objects can be reserved but not freed. This is by design and it is not a
+ * limitation. We do not want to introduce complexity induced by memory freeing,
+ * such as use-after-free bugs, memory fragmentation and so on.
+ *
+ * The object size and capacity of the pool are fixed at build time. So is the
+ * address of the objects back store.
+ */
+struct object_pool {
+       /* Size of 1 object in the pool in byte unit. */
+       const size_t obj_size;
+
+       /* Number of objects in the pool. */
+       const size_t capacity;
+
+       /* Objects back store. */
+       void *const objects;
+
+       /* How many objects are currently allocated. */
+       size_t used;
+};
+
+/* Create a static pool of objects. */
+#define OBJECT_POOL(_pool_name, _obj_backstore, _obj_size, _obj_count) \
+       struct object_pool _pool_name = {                               \
+               .objects = (_obj_backstore),                            \
+               .obj_size = (_obj_size),                                \
+               .capacity = (_obj_count),                               \
+               .used = 0U,                                             \
+       }
+
+/* Create a static pool of objects out of an array of pre-allocated objects. */
+#define OBJECT_POOL_ARRAY(_pool_name, _obj_array)                      \
+       OBJECT_POOL(_pool_name, (_obj_array),                           \
+                   sizeof((_obj_array)[0]), ARRAY_SIZE(_obj_array))
+
+/*
+ * Allocate 'count' objects from a pool.
+ * Return the address of the first object. Panic on error.
+ */
+static inline void *pool_alloc_n(struct object_pool *pool, size_t count)
+{
+       if (pool->used + count > pool->capacity) {
+               ERROR("Cannot allocate %zu objects out of pool (%zu objects left).\n",
+                     count, pool->capacity - pool->used);
+               panic();
+       }
+
+       void *obj = (char *)(pool->objects) + pool->obj_size * pool->used;
+       pool->used += count;
+       return obj;
+}
+
+/*
+ * Allocate 1 object from a pool.
+ * Return the address of the object. Panic on error.
+ */
+static inline void *pool_alloc(struct object_pool *pool)
+{
+       return pool_alloc_n(pool, 1U);
+}
+
+#endif /* OBJECT_POOL_H */