summaryrefslogblamecommitdiffstats
path: root/cpukit/libdl/rtl-allocator.c
blob: 988094060f42fc5f02f85b15ba0d36436220db0f (plain) (tree)





















































                                                                       
    

                                                                      
     








                                                            


                                                                        
                      

















































































































































                                                                              
/*
 *  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;
}