/*
  Allocate and return an new object.

  DESCRIPTION
    Pop an unused object from the stack or malloc it is the stack is empty.
    pin[0] is used, it's removed on return.
*/
void *_lf_alloc_new(LF_PINS *pins)
{
  LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg);
  uchar *node;
  for (;;)
  {
    do
    {
      node= allocator->top;
      _lf_pin(pins, 0, node);
    } while (node != allocator->top && LF_BACKOFF);
    if (!node)
    {
      node= (void *)my_malloc(allocator->element_size, MYF(MY_WME));
      if (allocator->constructor)
        allocator->constructor(node);
#ifdef MY_LF_EXTRA_DEBUG
      if (likely(node != 0))
        my_atomic_add32(&allocator->mallocs, 1);
#endif
      break;
    }
    if (my_atomic_casptr((void **)(char *)&allocator->top,
                         (void *)&node, anext_node(node)))
      break;
  }
  _lf_unpin(pins, 0);
  return node;
}
/*
  count the number of objects in a pool.

  NOTE
    This is NOT thread-safe !!!
*/
uint lf_alloc_pool_count(LF_ALLOCATOR *allocator)
{
  uint i;
  uchar *node;
  for (node= allocator->top, i= 0; node; node= anext_node(node), i++)
    /* no op */;
  return i;
}
Exemple #3
0
/*
  destroy the allocator, free everything that's in it

  NOTE
    As every other init/destroy function here and elsewhere it
    is not thread safe. No, this function is no different, ensure
    that no thread needs the allocator before destroying it.
    We are not responsible for any damage that may be caused by
    accessing the allocator when it is being or has been destroyed.
    Oh yes, and don't put your cat in a microwave.
*/
void lf_alloc_destroy(LF_ALLOCATOR *allocator)
{
  uchar *node= allocator->top;
  while (node)
  {
    uchar *tmp= anext_node(node);
    my_free(node);
    node= tmp;
  }
  lf_pinbox_destroy(&allocator->pinbox);
  allocator->top= 0;
}
/*
  destroy the allocator, free everything that's in it

  NOTE
    As every other init/destroy function here and elsewhere it
    is not thread safe. No, this function is no different, ensure
    that no thread needs the allocator before destroying it.
    We are not responsible for any damage that may be caused by
    accessing the allocator when it is being or has been destroyed.
    Oh yes, and don't put your cat in a microwave.
*/
void lf_alloc_destroy(LF_ALLOCATOR *allocator)
{
  uchar *node= allocator->top;
  while (node)
  {
    uchar *tmp= anext_node(node);
    if (allocator->destructor)
      allocator->destructor(node);
    my_free((void *)node, MYF(0));
    node= tmp;
  }
  lf_pinbox_destroy(&allocator->pinbox);
  allocator->top= 0;
}
/*
  callback for _lf_pinbox_real_free to free a list of unpinned objects -
  add it back to the allocator stack

  DESCRIPTION
    'first' and 'last' are the ends of the linked list of nodes:
    first->el->el->....->el->last. Use first==last to free only one element.
*/
static void alloc_free(uchar *first,
                       uchar volatile *last,
                       LF_ALLOCATOR *allocator)
{
  /*
    we need a union here to access type-punned pointer reliably.
    otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
  */
  union { uchar * node; void *ptr; } tmp;
  tmp.node= allocator->top;
  do
  {
    anext_node(last)= tmp.node;
  } while (!my_atomic_casptr((void **)(char *)&allocator->top,
                             (void **)&tmp.ptr, first) && LF_BACKOFF);
}