summaryrefslogtreecommitdiff
path: root/cpukit/libdl/rtl-bit-alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl/rtl-bit-alloc.c')
-rw-r--r--cpukit/libdl/rtl-bit-alloc.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/cpukit/libdl/rtl-bit-alloc.c b/cpukit/libdl/rtl-bit-alloc.c
new file mode 100644
index 0000000000..b7871f227b
--- /dev/null
+++ b/cpukit/libdl/rtl-bit-alloc.c
@@ -0,0 +1,197 @@
+/*
+ * COPYRIGHT (c) 2019 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtld
+ *
+ * @brief RTEMS Run-Time Link Editor Bit Allocator
+ *
+ * A configurable allocator for small peices of memory where embedding
+ * control blocks into the memory are not viable. The amount of memory
+ * should be small and the minimum allocator a 32bit work or higher.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rtems/rtl/rtl-allocator.h>
+#include "rtl-bit-alloc.h"
+#include "rtl-error.h"
+#include <rtems/rtl/rtl-trace.h>
+
+#define BITS_PER_WORD (sizeof (uint32_t) * 8)
+
+static size_t
+bit_blocks (rtems_rtl_bit_alloc* balloc, size_t size)
+{
+ if (size == 0)
+ return 0;
+ return ((size - 1) / balloc->block_size) + 1;
+}
+
+static size_t
+bit_word (size_t bit)
+{
+ return bit / BITS_PER_WORD;
+}
+
+static size_t
+bit_offset (size_t bit)
+{
+ return bit % (sizeof (uint32_t) * 8);
+}
+
+static uint32_t
+bit_mask (size_t bit)
+{
+ return 1 << bit_offset (bit);
+}
+
+static void
+bit_set (rtems_rtl_bit_alloc* balloc, size_t start, size_t bits)
+{
+ size_t b;
+ for (b = start; b < (start + bits); ++b)
+ balloc->bits[bit_word (b)] |= bit_mask (b);
+}
+
+static void
+bit_clear (rtems_rtl_bit_alloc* balloc, size_t start, size_t bits)
+{
+ size_t b;
+ for (b = start; b < (start + bits); ++b)
+ balloc->bits[bit_word (b)] &= ~bit_mask (b);
+}
+
+static ssize_t
+bit_find_clear (rtems_rtl_bit_alloc* balloc, size_t blocks)
+{
+ size_t base = 0;
+ size_t clear = 0;
+ size_t b;
+
+ for (b = 0; b < balloc->blocks; ++b)
+ {
+ if (balloc->bits[b] != 0xffffffff)
+ {
+ uint32_t word = balloc->bits[b];
+ size_t o;
+ for (o = 0; o < BITS_PER_WORD; ++o, word >>= 1)
+ {
+ if ((word & 1) == 0)
+ {
+ if (clear == 0)
+ base = (b * BITS_PER_WORD) + o;
+ ++clear;
+ if (clear == blocks)
+ return base;
+ }
+ else
+ {
+ clear = 0;
+ base = 0;
+ }
+ }
+ }
+ else
+ {
+ clear = 0;
+ base = 0;
+ }
+ }
+
+ return -1;
+}
+
+rtems_rtl_bit_alloc*
+rtems_rtl_bit_alloc_open (void* base, size_t size, size_t block_size, size_t used)
+{
+ rtems_rtl_bit_alloc* balloc;
+ const size_t base_size = base == NULL ? size : 0;;
+ const size_t blocks = (size / block_size) / BITS_PER_WORD;
+ const size_t bit_bytes = blocks * sizeof(uint32_t);
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_BIT_ALLOC))
+ printf ("rtl: balloc: open: base=%p size=%zu" \
+ " block-size=%zu blocks=%zu used=%zu\n",
+ base, size, block_size, blocks, used);
+
+ if (size == 0)
+ {
+ rtems_rtl_set_error (ENOMEM, "bit allocator size is 0");
+ return false;
+ }
+
+ if (used > size)
+ {
+ rtems_rtl_set_error (ENOMEM, "bad bit allocator used value");
+ return false;
+ }
+
+ balloc = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
+ sizeof (rtems_rtl_bit_alloc) + bit_bytes + base_size,
+ true);
+ if (balloc == NULL)
+ {
+ rtems_rtl_set_error (ENOMEM, "not bit allocator memory");
+ return NULL;
+ }
+
+ balloc->base =
+ base == NULL ? ((void*) balloc) + sizeof (rtems_rtl_bit_alloc) + bit_bytes: base;
+ balloc->size = size;
+ balloc->bits = ((void*) balloc) + sizeof (rtems_rtl_bit_alloc);
+ balloc->block_size = block_size;
+ balloc->blocks = blocks;
+
+ bit_set (balloc, 0, bit_blocks (balloc, used));
+
+ return balloc;
+}
+
+void
+rtems_rtl_bit_alloc_close (rtems_rtl_bit_alloc* balloc)
+{
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_BIT_ALLOC))
+ printf ("rtl: balloc: close: base=%p size=%zu\n",
+ balloc->base, balloc->size);
+ rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, balloc);
+}
+
+void*
+rtems_rtl_bit_alloc_balloc (rtems_rtl_bit_alloc* balloc, size_t size)
+{
+ size_t blocks = bit_blocks (balloc, size);
+ ssize_t block = bit_find_clear (balloc, blocks);
+ if (block < 0)
+ return NULL;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_BIT_ALLOC))
+ printf ("rtl: balloc: balloc: size=%zu blocks=%zu block=%zi\n",
+ size, blocks, block);
+ bit_set (balloc, block, blocks);
+ return (void*) (balloc->base + (block * balloc->block_size));
+}
+
+void
+rtems_rtl_bit_alloc_bfree (rtems_rtl_bit_alloc* balloc, void* addr, size_t size)
+{
+ const uint8_t* a = (const uint8_t*) addr;
+ if (addr != NULL && a >= balloc->base && a < balloc->base + balloc->size)
+ {
+ size_t block = bit_blocks (balloc, a - balloc->base);
+ size_t blocks = bit_blocks (balloc, size);
+ bit_clear (balloc, block, blocks);
+ }
+}