Skip to content

File lea_heap.c

File List > cubrid > src > heaplayers > lea_heap.c

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/* 
 * Following is Doug Lea's memory allocator with USE_MALLOC_INSTEAD 
 * feature amendment
 *
 * USE_MALLOC_INSTEAD
 * When this feature is enabled, uses system malloc/free instead of mmap/munmap.
 * 
 * ENABLE_SEPARATE_MMAP_EVENT_TRACE
 * Fix the problem that mmaped (malloced when USE_MALLOC_INSTEAD is 1)
 * memory region (which is returned by mmap_alloc function) is not
 * automatically freed when destroy_mspace is called.
 * 
 */

#include <stdlib.h>
#include <stddef.h>

#include "customheaps.h"
#include "error_manager.h"
#include "system_parameter.h"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

/* -------------------------------------------------------------------------- */
/* DL MALLOC ADAPTATION AND MODIFICATION LAYER */
/* -------------------------------------------------------------------------- */
/*
 * use malloc/free instead of mmap/munmap
 */

#define USE_MALLOC_INSTEAD 1
#define MOCK_LEA_HEAP_ID ((UINTPTR)(-1))
#define system_malloc my_malloc
#define system_free my_free

static void *my_malloc (size_t sz);
static int my_free (void *p);

/*
 * override  default DEFAULT_GRANULARITY
 */
#define DEFAULT_GRANULARITY (32U*1024U)

/*
 * prevent mremap use
 */
#if !defined(WINDOWS)
#if defined(linux)
#undef linux
#endif
#endif

/*
 * use mspace only
 */
#define ONLY_MSPACES 1

/*
 * Fix the problem that mmaped (malloced when USE_MALLOC_INSTEAD is 1)
 * memory region (which is returned by mmap_alloc function) is not
 * automatically freed when destroy_mspace is called.
 */
typedef struct mmap_trace_h_s MMAP_TRACE_H;
struct mmap_trace_h_s
{
  MMAP_TRACE_H *next;
  MMAP_TRACE_H *prev;
  void *ptr;
};

#define MMAP_TRACE_H_SIZE sizeof(MMAP_TRACE_H)

#define MMAP_TRACE_H_INIT(h, p) do {    \
  MMAP_TRACE_H *__h = (h);              \
  (__h)->next = (__h)->prev = (__h);    \
  (__h)->ptr = (p);                     \
} while (0)

#define MMAP_TRACE_H_REMOVE(h) do {     \
  MMAP_TRACE_H *__h = (h);              \
  (__h)->next->prev = (__h)->prev;      \
  (__h)->prev->next = (__h)->next;      \
} while (0)

#define MMAP_TRACE_H_ADD(p, h) do {     \
  MMAP_TRACE_H *__ih = (p);             \
  MMAP_TRACE_H *__bh = (h);             \
  (__ih)->prev = (__bh);                \
  (__ih)->next = (__bh)->next;          \
  (__bh)->next->prev = (__ih);          \
  (__bh)->next = (__ih);                \
} while (0)

static void mmap_called (void *m, void *ptr, MMAP_TRACE_H * h);
static void munmap_is_to_be_called (void *m, void *ptr, MMAP_TRACE_H * h);

#define ENABLE_SEPARATE_MMAP_EVENT_TRACE
#include "malloc_2_8_3.c"

/*
 * my_malloc - system_malloc hook function 
 *    return: memory allocated
 *    sz(in): request memory size
 */
static void *
my_malloc (size_t sz)
{
  void *ptr = malloc (sz);
  if (ptr != NULL)
    {
      return ptr;
    }
  else
    {
      return CMFAIL;
    }
}

/*
 * my_free -  system_free hook function
 *    return: memory allocated
 *    p(in):
 */
static int
my_free (void *p)
{
  free (p);
  return 0;
}

/* ------------------------------------------------------------------------- */
/* HL_LEA_HEAP IMPLEMENTATION */
/* ------------------------------------------------------------------------- */

typedef struct hl_mspace_s HL_MSPACE;
struct hl_mspace_s
{
  mstate ms;
  void *base;
  size_t base_size;
  MMAP_TRACE_H header;
};

/* Memory layout of HL_MSPACE
   +-----------+
   | HL_MSPACE |
   +-----------+ <-- 8 byte aligned. msp
   |           |     mstate (or mspace) m = chunk2mem(msp)
   +-----------+ <-- m
   |  mstate   |
   | ......... |

 */
#define mspace2hlmspace(m) \
  (HL_MSPACE *)((char *)mem2chunk(m) - ((sizeof (HL_MSPACE) + 7U) & ~7U))

/*
 * mmap_called - ENABLE_SEPARATE_MMAP_EVENT_TRACE hook function called after
 *               large chunk allocated
 *    return: void
 *    m(in): lea heap mspace pointer
 *    ptr(in): allocated chunk
 *    h(in): embedded trace header
 */
static void
mmap_called (void *m, void *ptr, MMAP_TRACE_H * h)
{
  HL_MSPACE *hms = mspace2hlmspace (m);
  MMAP_TRACE_H_INIT (h, ptr);
  MMAP_TRACE_H_ADD (h, &hms->header);
}

/*
 * munmap_is_to_be_called - ENABLE_SEPARATE_MMAP_EVENT_TRACE hook function 
 *                          called before large chunk is to be freed.
 *    return: void
 *    m(in): lea heap mspace pointer
 *    ptr(in): memory chunk
 *    h(in): embedded trace header
 */
static void
munmap_is_to_be_called (void *m, void *ptr, MMAP_TRACE_H * h)
{
  HL_MSPACE *hms = mspace2hlmspace (m);
  assert (h->ptr == ptr);
  MMAP_TRACE_H_REMOVE (h);
}

/* EXPORTED FUNCTIONS */
#define LEA_HEAP_BASE_SIZE (64U*1024U)

/*
 * hl_register_lea_heap - register new lea heap instance
 *    return: heap handle
 */
UINTPTR
hl_register_lea_heap (void)
{
#if !defined (NDEBUG)
  if (prm_get_bool_value (PRM_ID_USE_SYSTEM_MALLOC))
    {
      return MOCK_LEA_HEAP_ID;
    }
  else
#endif /* !NDEBUG */
    {
      HL_MSPACE *hms;

      hms = (HL_MSPACE *) malloc (LEA_HEAP_BASE_SIZE);
      if (hms == NULL)
    {
      return 0;
    }

      hms->base = (char *) hms + ((sizeof (*hms) + 7U) & ~7U);
      hms->base_size = LEA_HEAP_BASE_SIZE - (size_t) ((char *) hms->base - (char *) hms);
      MMAP_TRACE_H_INIT (&hms->header, NULL);

      hms->ms = (mstate) create_mspace_with_base (hms->base, hms->base_size, 0);
      if (hms->ms == NULL)
    {
      free (hms);
      return 0;
    }

      return ((UINTPTR) hms);
    }
}

/*
 * destroy_mspace_internal - see unregister_leap_heap 
 *    return: void
 *    hms(in): leap heap mspace pointer
 */
static void
destroy_mspace_internal (HL_MSPACE * hms)
{
  destroy_mspace (hms->ms);
  hms->ms = NULL;
  /* remove unmapped segments */
  while (hms->header.next != &hms->header)
    {
      MMAP_TRACE_H *h = hms->header.next;
      MMAP_TRACE_H_REMOVE (h);  /* unlink from doubley linked list */
      my_free (h->ptr);     /* no need to free h. h is embedded */
    }
}


/*
 * hl_clear_lea_heap - clears lea heap
 *    return: void
 *    heap_id(in): lea heap handle
 */
void
hl_clear_lea_heap (UINTPTR heap_id)
{
#if !defined (NDEBUG)
  if (prm_get_bool_value (PRM_ID_USE_SYSTEM_MALLOC))
    {
      assert (heap_id == MOCK_LEA_HEAP_ID);
    }
  else
#endif /* !NDEBUG */
    {
      HL_MSPACE *hms = (HL_MSPACE *) heap_id;

      if (hms != NULL)
    {
      destroy_mspace_internal (hms);
      hms->ms = (mstate) create_mspace_with_base (hms->base, hms->base_size, 0);
      assert (hms->ms != NULL);
    }
    }
}

/*
 * hl_unregister_lea_heap - destoyes lea heap
 *    return: void
 *    heap_id(in): lea heap handle
 */
void
hl_unregister_lea_heap (UINTPTR heap_id)
{
#if !defined (NDEBUG)
  if (prm_get_bool_value (PRM_ID_USE_SYSTEM_MALLOC))
    {
      assert (heap_id == MOCK_LEA_HEAP_ID);
    }
  else
#endif /* !NDEBUG */
    {
      HL_MSPACE *hms = (HL_MSPACE *) heap_id;

      if (hms != NULL)
    {
      destroy_mspace_internal (hms);
      free (hms);
    }
    }
}

/*
 * hl_lea_alloc - alloc
 *    return: pointer to allocated memory
 *    heap_id(in): lea heap handle
 *    sz(in): requested size
 */
void *
hl_lea_alloc (UINTPTR heap_id, size_t sz)
{
#if !defined (NDEBUG)
  if (prm_get_bool_value (PRM_ID_USE_SYSTEM_MALLOC))
    {
      return malloc (sz);
    }
  else
#endif /* !NDEBUG */
    {
      HL_MSPACE *hms = (HL_MSPACE *) heap_id;
      void *p;

      if (hms != NULL)
    {
      p = mspace_malloc (hms->ms, sz);
      if (p == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sz);
        }

      return p;
    }
      return NULL;
    }
}

/*
 * hl_lea_realloc - realloc
 *    return: pointer to re-allocated memory
 *    heap_id(in): lea heap handle
 *    ptr(in): pointer to memory block allocated before
 *    sz(in): requested size
 */
void *
hl_lea_realloc (UINTPTR heap_id, void *ptr, size_t sz)
{
#if !defined (NDEBUG)
  if (prm_get_bool_value (PRM_ID_USE_SYSTEM_MALLOC))
    {
      return realloc (ptr, sz);
    }
  else
#endif /* !NDEBUG */
    {
      HL_MSPACE *hms = (HL_MSPACE *) heap_id;
      void *p;

      if (hms != NULL)
    {
      p = mspace_realloc (hms->ms, ptr, sz);
      if (p == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sz);
        }

      return p;
    }
      return NULL;
    }
}

/*
 * hl_lea_free - free
 *    return: void
 *    heap_id(in): lea heap handle
 *    ptr(in): pointer to memory block allocated before
 */
void
hl_lea_free (UINTPTR heap_id, void *ptr)
{
#if !defined (NDEBUG)
  if (prm_get_bool_value (PRM_ID_USE_SYSTEM_MALLOC))
    {
      free (ptr);
    }
  else
#endif /* !NDEBUG */
    {
      HL_MSPACE *hms = (HL_MSPACE *) heap_id;

      if (hms != NULL)
    {
      mspace_free (hms->ms, ptr);
    }
    }
}