forked from Imagelibrary/rtems
Use the following variant which was already used by most source files: #ifdef HAVE_CONFIG_H #include "config.h" #endif
198 lines
4.6 KiB
C
198 lines
4.6 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef 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);
|
|
}
|
|
}
|