summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl/rtl-allocator.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl/rtl-allocator.c')
-rw-r--r--cpukit/libdl/rtl-allocator.c210
1 files changed, 210 insertions, 0 deletions
diff --git a/cpukit/libdl/rtl-allocator.c b/cpukit/libdl/rtl-allocator.c
new file mode 100644
index 0000000000..b845013fd8
--- /dev/null
+++ b/cpukit/libdl/rtl-allocator.c
@@ -0,0 +1,210 @@
+/*
+ * 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;
+
+ 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);
+
+ if (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;
+}