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