added realloc to xma
This commit is contained in:
@ -23,6 +23,7 @@
|
||||
|
||||
#define ALIGN QSE_SIZEOF(qse_size_t)
|
||||
#define HDRSIZE QSE_SIZEOF(qse_xma_blk_t)
|
||||
#define MINBLKLEN (HDRSIZE + ALIGN)
|
||||
|
||||
#define SYS_TO_USR(_) (((qse_xma_blk_t*)_) + 1)
|
||||
#define USR_TO_SYS(_) (((qse_xma_blk_t*)_) - 1)
|
||||
@ -34,9 +35,6 @@
|
||||
*/
|
||||
#define FIXED QSE_XMA_FIXED
|
||||
#define XFIMAX(xma) (QSE_COUNTOF(xma->xfree)-1)
|
||||
#define _XFI(size) (((size) / ALIGN) - 1)
|
||||
#define _XFI_LARGE(xma,size) (szlog2(size) - (xma)->bdec + FIXED)
|
||||
#define XFI(xma,size) ((_XFI(size) < FIXED)? _XFI(size): _XFI_LARGE(xma,size))
|
||||
|
||||
struct qse_xma_blk_t
|
||||
{
|
||||
@ -58,7 +56,7 @@ struct qse_xma_blk_t
|
||||
|
||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (xma)
|
||||
|
||||
static QSE_INLINE qse_size_t szlog2 (qse_size_t n)
|
||||
static QSE_INLINE_ALWAYS qse_size_t szlog2 (qse_size_t n)
|
||||
{
|
||||
/*
|
||||
* 2**x = n;
|
||||
@ -98,6 +96,14 @@ static QSE_INLINE qse_size_t szlog2 (qse_size_t n)
|
||||
#undef BITS
|
||||
}
|
||||
|
||||
static QSE_INLINE_ALWAYS qse_size_t getxfi (qse_xma_t* xma, qse_size_t size)
|
||||
{
|
||||
qse_size_t xfi = ((size) / ALIGN) - 1;
|
||||
if (xfi >= FIXED) xfi = szlog2(size) - (xma)->bdec + FIXED;
|
||||
if (xfi > XFIMAX(xma)) xfi = XFIMAX(xma);
|
||||
return xfi;
|
||||
}
|
||||
|
||||
qse_xma_t* qse_xma_open (qse_mmgr_t* mmgr, qse_size_t ext, qse_size_t size)
|
||||
{
|
||||
qse_xma_t* xma;
|
||||
@ -135,8 +141,9 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t size)
|
||||
qse_xma_blk_t* free;
|
||||
qse_size_t xfi;
|
||||
|
||||
size = ((size + ALIGN - 1) / ALIGN) * ALIGN;
|
||||
/* adjust 'size' to be large enough to hold a single smallest block */
|
||||
if (size < HDRSIZE + ALIGN) size = HDRSIZE + ALIGN;
|
||||
if (size < MINBLKLEN) size = MINBLKLEN;
|
||||
|
||||
/* allocate a memory chunk to use for actual memory allocation */
|
||||
free = QSE_MMGR_ALLOC (mmgr, size);
|
||||
@ -155,8 +162,7 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t size)
|
||||
xma->bdec = szlog2(FIXED*ALIGN); /* precalculate the decrement value */
|
||||
|
||||
/* the entire chunk is a free block */
|
||||
xfi = XFI(xma,free->size);
|
||||
if (xfi > XFIMAX(xma)) xfi = XFIMAX(xma);
|
||||
xfi = getxfi(xma,free->size);
|
||||
xma->xfree[xfi] = free; /* locate it at the right slot */
|
||||
xma->head = free; /* store it for furture reference */
|
||||
|
||||
@ -179,8 +185,7 @@ void qse_xma_fini (qse_xma_t* xma)
|
||||
|
||||
static QSE_INLINE void attach_to_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
|
||||
{
|
||||
qse_size_t xfi = XFI(xma,b->size);
|
||||
if (xfi > XFIMAX(xma)) xfi = XFIMAX(xma);
|
||||
qse_size_t xfi = getxfi(xma,b->size);
|
||||
|
||||
b->f.prev = QSE_NULL;
|
||||
b->f.next = xma->xfree[xfi];
|
||||
@ -201,9 +206,7 @@ static QSE_INLINE void detach_from_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_size_t xfi = XFI(xma,b->size);
|
||||
if (xfi > XFIMAX(xma)) xfi = XFIMAX(xma);
|
||||
|
||||
qse_size_t xfi = getxfi(xma,b->size);
|
||||
QSE_ASSERT (b == xma->xfree[xfi]);
|
||||
xma->xfree[xfi] = n;
|
||||
}
|
||||
@ -222,7 +225,7 @@ static qse_xma_blk_t* alloc_from_freelist (
|
||||
detach_from_freelist (xma, free);
|
||||
|
||||
qse_size_t rem = free->size - size;
|
||||
if (rem > HDRSIZE)
|
||||
if (rem >= MINBLKLEN)
|
||||
{
|
||||
qse_xma_blk_t* tmp;
|
||||
|
||||
@ -292,8 +295,7 @@ void* qse_xma_alloc (qse_xma_t* xma, qse_size_t size)
|
||||
size = ((size + ALIGN - 1) / ALIGN) * ALIGN;
|
||||
|
||||
QSE_ASSERT (size >= ALIGN);
|
||||
xfi = XFI(xma,size);
|
||||
if (xfi > XFIMAX(xma)) xfi = XFIMAX(xma);
|
||||
xfi = getxfi(xma,size);
|
||||
|
||||
/*if (xfi < XFIMAX(xma) && xma->xfree[xfi])*/
|
||||
if (xfi < FIXED && xma->xfree[xfi])
|
||||
@ -354,10 +356,205 @@ void* qse_xma_alloc (qse_xma_t* xma, qse_size_t size)
|
||||
return SYS_TO_USR(free);
|
||||
}
|
||||
|
||||
static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t size)
|
||||
{
|
||||
qse_xma_blk_t* blk = USR_TO_SYS(b);
|
||||
|
||||
if (size > blk->size)
|
||||
{
|
||||
qse_size_t req = size - blk->size;
|
||||
qse_xma_blk_t* n;
|
||||
qse_size_t rem;
|
||||
|
||||
n = blk->b.next;
|
||||
if (!n || !n->avail || req > n->size) return QSE_NULL;
|
||||
|
||||
/* merge the current block with the next block
|
||||
* if it is available */
|
||||
|
||||
detach_from_freelist (xma, n);
|
||||
|
||||
rem = (HDRSIZE + n->size) - req;
|
||||
if (rem >= MINBLKLEN)
|
||||
{
|
||||
qse_xma_blk_t* tmp;
|
||||
/* store n->b.next in case 'tmp' begins somewhere
|
||||
* in the header part of n */
|
||||
qse_xma_blk_t* nn = n->b.next;
|
||||
|
||||
tmp = (qse_xma_blk_t*)(((qse_byte_t*)n) + req);
|
||||
|
||||
tmp->avail = 1;
|
||||
tmp->size = rem - HDRSIZE;
|
||||
attach_to_freelist (xma, tmp);
|
||||
|
||||
blk->size += req;
|
||||
|
||||
tmp->b.next = nn;
|
||||
if (nn) nn->b.prev = tmp;
|
||||
|
||||
blk->b.next = tmp;
|
||||
tmp->b.prev = blk;
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.alloc += req;
|
||||
xma->stat.avail -= req; /* req + HDRSIZE(tmp) - HDRSIZE(n) */
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
blk->size += HDRSIZE + n->size;
|
||||
blk->b.next = n->b.next;
|
||||
if (n->b.next) n->b.next->b.prev = blk;
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.nfree--;
|
||||
xma->stat.alloc += HDRSIZE + n->size;
|
||||
xma->stat.avail -= n->size;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_size_t total = 0;
|
||||
qse_xma_blk_t* x = QSE_NULL;
|
||||
|
||||
/* find continuous blocks available to accomodate
|
||||
* additional space required */
|
||||
for (n = blk->b.next; n && n->avail; n = n->b.next)
|
||||
{
|
||||
total += n->size + HDRSIZE;
|
||||
if (req <= total)
|
||||
{
|
||||
x = n;
|
||||
break;
|
||||
}
|
||||
n = n->b.next;
|
||||
}
|
||||
|
||||
if (!x)
|
||||
{
|
||||
/* no such blocks. return failure */
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
for (n = blk->b.next; n != x; n = n->b.next)
|
||||
{
|
||||
detach_from_freelist (xma, n);
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.nfree--;
|
||||
#endif
|
||||
}
|
||||
|
||||
detach_from_freelist (xma, x);
|
||||
|
||||
rem = total - req;
|
||||
if (rem >= MINBLKLEN)
|
||||
{
|
||||
qse_xma_blk_t* tmp;
|
||||
|
||||
tmp = (qse_xma_blk_t*)(((qse_byte_t*)(blk->b.next + 1)) + req);
|
||||
tmp->avail = 1;
|
||||
tmp->size = rem - HDRSIZE;
|
||||
|
||||
attach_to_freelist (xma, tmp);
|
||||
|
||||
blk->size += req;
|
||||
|
||||
tmp->b.next = x->b.next;
|
||||
if (x->b.next) x->b.next->b.prev = tmp;
|
||||
|
||||
blk->b.next = tmp;
|
||||
tmp->b.prev = blk;
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.alloc += req;
|
||||
xma->stat.avail -= req + HDRSIZE;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
blk->size += total;
|
||||
blk->b.next = x->b.next;
|
||||
if (x->b.next) x->b.next->b.prev = blk;
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.nfree--;
|
||||
xma->stat.alloc += total;
|
||||
xma->stat.avail -= total;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (size < blk->size)
|
||||
{
|
||||
qse_size_t rem = blk->size - size;
|
||||
if (rem >= MINBLKLEN)
|
||||
{
|
||||
qse_xma_blk_t* tmp;
|
||||
|
||||
/* the leftover is large enough to hold a block
|
||||
* of minimum size. split the current block.
|
||||
* let 'tmp' point to the leftover. */
|
||||
tmp = (qse_xma_blk_t*)(((qse_byte_t*)(blk + 1)) + size);
|
||||
tmp->avail = 1;
|
||||
tmp->size = rem - HDRSIZE;
|
||||
|
||||
/* link 'tmp' to the block list */
|
||||
tmp->b.next = blk->b.next;
|
||||
tmp->b.prev = blk;
|
||||
if (blk->b.next) blk->b.next->b.prev = tmp;
|
||||
blk->b.next = tmp;
|
||||
blk->size = size;
|
||||
|
||||
/* add 'tmp' to the free list */
|
||||
attach_to_freelist (xma, tmp);
|
||||
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
/* TODO: if the next block is free. need to merge tmp with that..... */
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.nfree++;
|
||||
xma->stat.alloc -= rem;
|
||||
xma->stat.avail += tmp->size;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void* qse_xma_realloc (qse_xma_t* xma, void* b, qse_size_t size)
|
||||
{
|
||||
/* TODO */
|
||||
return QSE_NULL;
|
||||
void* n;
|
||||
|
||||
if (b == QSE_NULL)
|
||||
{
|
||||
/* 'realloc' with NULL is the same as 'alloc' */
|
||||
n = qse_xma_alloc (xma, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* try reallocation by merging the adjacent continuous blocks */
|
||||
n = _realloc_merge (xma, b, size);
|
||||
if (n == QSE_NULL)
|
||||
{
|
||||
/* reallocation by merging failed. fall back to the slow
|
||||
* allocation-copy-free scheme */
|
||||
n = qse_xma_alloc (xma, size);
|
||||
if (n)
|
||||
{
|
||||
QSE_MEMCPY (n, b, size);
|
||||
qse_xma_free (xma, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
@ -399,7 +596,8 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
qse_xma_blk_t* x = blk->b.prev;
|
||||
qse_xma_blk_t* y = blk->b.next;
|
||||
qse_xma_blk_t* z = y->b.next;
|
||||
qse_size_t bs = blk->size + HDRSIZE + y->size + HDRSIZE;
|
||||
qse_size_t ns = HDRSIZE + blk->size + HDRSIZE;
|
||||
qse_size_t bs = ns + y->size;
|
||||
|
||||
detach_from_freelist (xma, x);
|
||||
detach_from_freelist (xma, y);
|
||||
@ -412,7 +610,7 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.nfree--;
|
||||
xma->stat.avail += bs;
|
||||
xma->stat.avail += ns;
|
||||
#endif
|
||||
}
|
||||
else if (blk->b.next && blk->b.next->avail)
|
||||
@ -440,7 +638,10 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
*/
|
||||
qse_xma_blk_t* x = blk->b.next;
|
||||
qse_xma_blk_t* y = x->b.next;
|
||||
qse_size_t bs = x->size + HDRSIZE;
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.avail += blk->size + HDRSIZE;
|
||||
#endif
|
||||
|
||||
/* detach x from the free list */
|
||||
detach_from_freelist (xma, x);
|
||||
@ -448,7 +649,7 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
/* update the block availability */
|
||||
blk->avail = 1;
|
||||
/* update the block size. HDRSIZE for the header space in x */
|
||||
blk->size += bs;
|
||||
blk->size += HDRSIZE + x->size;
|
||||
|
||||
/* update the backward link of Y */
|
||||
if (y) y->b.prev = blk;
|
||||
@ -458,9 +659,6 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
/* attach blk to the free list */
|
||||
attach_to_freelist (xma, blk);
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.avail += bs;
|
||||
#endif
|
||||
}
|
||||
else if (blk->b.prev && blk->b.prev->avail)
|
||||
{
|
||||
@ -488,19 +686,18 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
*/
|
||||
qse_xma_blk_t* x = blk->b.prev;
|
||||
qse_xma_blk_t* y = blk->b.next;
|
||||
qse_size_t bs = blk->size + HDRSIZE;
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.avail += HDRSIZE + blk->size;
|
||||
#endif
|
||||
|
||||
detach_from_freelist (xma, x);
|
||||
|
||||
x->size += bs;
|
||||
x->size += HDRSIZE + blk->size;
|
||||
x->b.next = y;
|
||||
if (y) y->b.prev = x;
|
||||
|
||||
attach_to_freelist (xma, x);
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
xma->stat.avail += bs;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -514,36 +711,45 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void qse_xma_dump (qse_xma_t* xma)
|
||||
{
|
||||
qse_xma_blk_t* tmp;
|
||||
unsigned long long fsum, asum, isum;
|
||||
unsigned long long fsum, asum;
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
unsigned long long isum;
|
||||
#endif
|
||||
|
||||
printf ("<MMP DUMP>\n");
|
||||
printf ("== statistics ==\n");
|
||||
printf ("total = %llu\n", (unsigned long long)xma->stat.total);
|
||||
printf ("alloc = %llu\n", (unsigned long long)xma->stat.alloc);
|
||||
printf ("avail = %llu\n", (unsigned long long)xma->stat.avail);
|
||||
qse_printf (QSE_T("<XMA DUMP>\n"));
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
qse_printf (QSE_T("== statistics ==\n"));
|
||||
qse_printf (QSE_T("total = %llu\n"), (unsigned long long)xma->stat.total);
|
||||
qse_printf (QSE_T("alloc = %llu\n"), (unsigned long long)xma->stat.alloc);
|
||||
qse_printf (QSE_T("avail = %llu\n"), (unsigned long long)xma->stat.avail);
|
||||
#endif
|
||||
|
||||
printf ("== blocks ==\n");
|
||||
printf (" size avail address\n");
|
||||
qse_printf (QSE_T("== blocks ==\n"));
|
||||
qse_printf (QSE_T(" size avail address\n"));
|
||||
for (tmp = xma->head, fsum = 0, asum = 0; tmp; tmp = tmp->b.next)
|
||||
{
|
||||
printf (" %-18llu %-5d %p\n", (unsigned long long)tmp->size, tmp->avail, tmp);
|
||||
qse_printf (QSE_T(" %-18llu %-5d %p\n"), (unsigned long long)tmp->size, tmp->avail, tmp);
|
||||
if (tmp->avail) fsum += tmp->size;
|
||||
else asum += tmp->size;
|
||||
}
|
||||
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
isum = (xma->stat.nfree + xma->stat.nused) * HDRSIZE;
|
||||
#endif
|
||||
|
||||
printf ("---------------------------------------\n");
|
||||
printf ("Allocated blocks: %18llu bytes\n", asum);
|
||||
printf ("Available blocks: %18llu bytes\n", fsum);
|
||||
printf ("Internal use : %18llu bytes\n", isum);
|
||||
printf ("Total : %18llu bytes\n", asum + fsum + isum);
|
||||
qse_printf (QSE_T("---------------------------------------\n"));
|
||||
qse_printf (QSE_T("Allocated blocks: %18llu bytes\n"), asum);
|
||||
qse_printf (QSE_T("Available blocks: %18llu bytes\n"), fsum);
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
qse_printf (QSE_T("Internal use : %18llu bytes\n"), isum);
|
||||
qse_printf (QSE_T("Total : %18llu bytes\n"), asum + fsum + isum);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main ()
|
||||
{
|
||||
int i;
|
||||
|
Reference in New Issue
Block a user