forked from Imagelibrary/rtems
218 lines
5.5 KiB
C
218 lines
5.5 KiB
C
/*
|
|
* COPYRIGHT (c) 2012 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_rtl
|
|
*
|
|
* @brief RTEMS Run-Time Linker Allocator
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <rtems/rtl/rtl.h>
|
|
#include "rtl-alloc-heap.h"
|
|
#include "rtl-trace.h"
|
|
|
|
/**
|
|
* Tags as symbols for tracing.
|
|
*/
|
|
#if RTEMS_RTL_TRACE
|
|
static const char* tag_labels[6] =
|
|
{
|
|
"OBJECT",
|
|
"SYMBOL",
|
|
"EXTERNAL",
|
|
"READ",
|
|
"READ_WRITE",
|
|
"READ_EXEC",
|
|
};
|
|
#define rtems_rtl_trace_tag_label(_l) tag_labels[_l]
|
|
#else
|
|
#define rtems_rtl_trace_tag_label(_l) ""
|
|
#endif
|
|
|
|
void
|
|
rtems_rtl_alloc_initialise (rtems_rtl_alloc_data_t* data)
|
|
{
|
|
int c;
|
|
data->allocator = rtems_rtl_alloc_heap;
|
|
for (c = 0; c < RTEMS_RTL_ALLOC_TAGS; ++c)
|
|
rtems_chain_initialize_empty (&data->indirects[c]);
|
|
}
|
|
|
|
void*
|
|
rtems_rtl_alloc_new (rtems_rtl_alloc_tag_t tag, size_t size, bool zero)
|
|
{
|
|
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
|
void* address = NULL;
|
|
|
|
/*
|
|
* Obtain memory from the allocator. The address field is set by the
|
|
* allocator.
|
|
*/
|
|
if (rtl)
|
|
rtl->allocator.allocator (true, tag, &address, size);
|
|
|
|
rtems_rtl_unlock ();
|
|
|
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
|
|
printf ("rtl: alloc: new: %s addr=%p size=%zu\n",
|
|
rtems_rtl_trace_tag_label (tag), address, size);
|
|
|
|
/*
|
|
* Only zero the memory if asked to and the allocation was successful.
|
|
*/
|
|
if (address && zero)
|
|
memset (address, 0, size);
|
|
|
|
return address;
|
|
}
|
|
|
|
void
|
|
rtems_rtl_alloc_del (rtems_rtl_alloc_tag_t tag, void* address)
|
|
{
|
|
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
|
|
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
|
|
printf ("rtl: alloc: del: %s addr=%p\n",
|
|
rtems_rtl_trace_tag_label (tag), address);
|
|
|
|
if (rtl && address)
|
|
rtl->allocator.allocator (false, tag, &address, 0);
|
|
|
|
rtems_rtl_unlock ();
|
|
}
|
|
|
|
rtems_rtl_allocator_t
|
|
rtems_rtl_alloc_hook (rtems_rtl_allocator_t handler)
|
|
{
|
|
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
|
rtems_rtl_allocator_t previous = rtl->allocator.allocator;
|
|
rtl->allocator.allocator = handler;
|
|
rtems_rtl_unlock ();
|
|
return previous;
|
|
}
|
|
|
|
void
|
|
rtems_rtl_alloc_indirect_new (rtems_rtl_alloc_tag_t tag,
|
|
rtems_rtl_ptr_t* handle,
|
|
size_t size)
|
|
{
|
|
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
|
|
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
|
|
{
|
|
if (!rtems_rtl_ptr_null (handle))
|
|
printf ("rtl: alloc: inew: %s handle=%p: not null\n",
|
|
rtems_rtl_trace_tag_label (tag), handle);
|
|
printf ("rtl: alloc: inew: %s handle=%p size=%zd\n",
|
|
rtems_rtl_trace_tag_label (tag), handle, size);
|
|
}
|
|
|
|
if (rtl)
|
|
{
|
|
rtems_rtl_alloc_data_t* allocator = &rtl->allocator;
|
|
handle->pointer = rtems_rtl_alloc_new (tag, size, false);
|
|
if (!rtems_rtl_ptr_null (handle))
|
|
rtems_chain_append_unprotected (&allocator->indirects[tag],
|
|
&handle->node);
|
|
}
|
|
|
|
rtems_rtl_unlock ();
|
|
}
|
|
|
|
void
|
|
rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
|
|
rtems_rtl_ptr_t* handle)
|
|
{
|
|
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
|
|
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
|
|
{
|
|
if (rtems_rtl_ptr_null (handle))
|
|
printf ("rtl: alloc: idel: %s handle=%p: is null\n",
|
|
rtems_rtl_trace_tag_label (tag), handle);
|
|
printf ("rtl: alloc: idel: %s handle=%p\n",
|
|
rtems_rtl_trace_tag_label (tag), handle);
|
|
}
|
|
|
|
if (rtl && !rtems_rtl_ptr_null (handle))
|
|
{
|
|
rtems_chain_extract_unprotected (&handle->node);
|
|
rtems_rtl_alloc_del (tag, &handle->pointer);
|
|
}
|
|
}
|
|
|
|
bool
|
|
rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
|
void** const_base, size_t const_size,
|
|
void** data_base, size_t data_size,
|
|
void** bss_base, size_t bss_size)
|
|
{
|
|
*text_base = *const_base = *data_base = *bss_base = NULL;
|
|
|
|
if (text_size)
|
|
{
|
|
*text_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ_EXEC,
|
|
text_size, false);
|
|
if (!*text_base)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (const_size)
|
|
{
|
|
*const_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ,
|
|
const_size, false);
|
|
if (!*const_base)
|
|
{
|
|
rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (data_size)
|
|
{
|
|
*data_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ_WRITE,
|
|
data_size, false);
|
|
if (!*data_base)
|
|
{
|
|
rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (bss_size)
|
|
{
|
|
*bss_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ_WRITE,
|
|
bss_size, false);
|
|
if (!*bss_base)
|
|
{
|
|
rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
rtems_rtl_alloc_module_del (void** text_base,
|
|
void** const_base,
|
|
void** data_base,
|
|
void** bss_base)
|
|
{
|
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *bss_base);
|
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *data_base);
|
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_base);
|
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_EXEC, *text_base);
|
|
*text_base = *const_base = *data_base = *bss_base = NULL;
|
|
}
|