added fixed-size block allocator
This commit is contained in:
@ -5,7 +5,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
lib_LTLIBRARIES = libqsecmn.la
|
||||
libqsecmn_la_SOURCES = \
|
||||
syscall.h mem.h \
|
||||
xma.c mem.c chr.c chr_cnv.c rex.c \
|
||||
mem.c xma.c fma.c chr.c chr_cnv.c rex.c \
|
||||
str_bas.c str_cnv.c str_dyn.c str_utl.c \
|
||||
lda.c htb.c rbt.c sll.c dll.c opt.c \
|
||||
tio.c tio_get.c tio_put.c \
|
||||
|
@ -73,11 +73,11 @@ am__base_list = \
|
||||
am__installdirs = "$(DESTDIR)$(libdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libqsecmn_la_DEPENDENCIES =
|
||||
am_libqsecmn_la_OBJECTS = xma.lo mem.lo chr.lo chr_cnv.lo rex.lo \
|
||||
str_bas.lo str_cnv.lo str_dyn.lo str_utl.lo lda.lo htb.lo \
|
||||
rbt.lo sll.lo dll.lo opt.lo tio.lo tio_get.lo tio_put.lo \
|
||||
fio.lo pio.lo sio.lo time.lo misc.lo assert.lo main.lo \
|
||||
stdio.lo
|
||||
am_libqsecmn_la_OBJECTS = mem.lo xma.lo fma.lo chr.lo chr_cnv.lo \
|
||||
rex.lo str_bas.lo str_cnv.lo str_dyn.lo str_utl.lo lda.lo \
|
||||
htb.lo rbt.lo sll.lo dll.lo opt.lo tio.lo tio_get.lo \
|
||||
tio_put.lo fio.lo pio.lo sio.lo time.lo misc.lo assert.lo \
|
||||
main.lo stdio.lo
|
||||
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
|
||||
libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
@ -262,7 +262,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
lib_LTLIBRARIES = libqsecmn.la $(am__append_1)
|
||||
libqsecmn_la_SOURCES = \
|
||||
syscall.h mem.h \
|
||||
xma.c mem.c chr.c chr_cnv.c rex.c \
|
||||
mem.c xma.c fma.c chr.c chr_cnv.c rex.c \
|
||||
str_bas.c str_cnv.c str_dyn.c str_utl.c \
|
||||
lda.c htb.c rbt.c sll.c dll.c opt.c \
|
||||
tio.c tio_get.c tio_put.c \
|
||||
@ -362,6 +362,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr_cnv.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
|
||||
|
139
qse/lib/cmn/fma.c
Normal file
139
qse/lib/cmn/fma.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright 2006-2009 Chung, Hyung-Hwan.
|
||||
This file is part of QSE.
|
||||
|
||||
QSE is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
QSE is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <qse/cmn/fma.h>
|
||||
#include "mem.h"
|
||||
|
||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (fma)
|
||||
|
||||
qse_fma_t* qse_fma_open (
|
||||
qse_mmgr_t* mmgr, qse_size_t xtnsize,
|
||||
qse_size_t blksize, qse_size_t maxblks, qse_size_t maxcnks)
|
||||
{
|
||||
qse_fma_t* fma;
|
||||
|
||||
if (mmgr == QSE_NULL)
|
||||
{
|
||||
mmgr = QSE_MMGR_GETDFL();
|
||||
|
||||
QSE_ASSERTX (mmgr != QSE_NULL,
|
||||
"Set the memory manager with QSE_MMGR_SETDFL()");
|
||||
|
||||
if (mmgr == QSE_NULL) return QSE_NULL;
|
||||
}
|
||||
|
||||
fma = (qse_fma_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(*fma) + xtnsize);
|
||||
if (fma == QSE_NULL) return QSE_NULL;
|
||||
|
||||
if (qse_fma_init (fma, mmgr, blksize, maxblks, maxcnks) == QSE_NULL)
|
||||
{
|
||||
QSE_MMGR_FREE (mmgr, fma);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
return fma;
|
||||
}
|
||||
|
||||
void qse_fma_close (qse_fma_t* fma)
|
||||
{
|
||||
qse_fma_fini (fma);
|
||||
QSE_MMGR_FREE (fma->mmgr, fma);
|
||||
}
|
||||
|
||||
qse_fma_t* qse_fma_init (
|
||||
qse_fma_t* fma, qse_mmgr_t* mmgr,
|
||||
qse_size_t blksize, qse_size_t maxblks, qse_size_t maxcnks)
|
||||
{
|
||||
QSE_MEMSET (fma, 0, QSE_SIZEOF(*fma));
|
||||
fma->mmgr = mmgr;
|
||||
|
||||
if (blksize <= QSE_SIZEOF(qse_fma_blk_t))
|
||||
blksize = QSE_SIZEOF(qse_fma_blk_t);
|
||||
if (maxblks <= 0) maxblks = 1;
|
||||
if (maxcnks <= 0) maxcnks = 1;
|
||||
|
||||
fma->blksize = blksize;
|
||||
fma->maxblks = maxblks;
|
||||
fma->maxcnks = maxcnks;
|
||||
|
||||
return fma;
|
||||
}
|
||||
|
||||
void qse_fma_fini (qse_fma_t* fma)
|
||||
{
|
||||
while (fma->cnkhead)
|
||||
{
|
||||
qse_fma_cnk_t* next = fma->cnkhead->next;
|
||||
QSE_MMGR_FREE (fma->mmgr, fma->cnkhead);
|
||||
fma->cnkhead = next;
|
||||
}
|
||||
}
|
||||
|
||||
static QSE_INLINE qse_fma_cnk_t* add_chunk (qse_fma_t* fma)
|
||||
{
|
||||
qse_fma_cnk_t* cnk;
|
||||
qse_fma_blk_t* blk;
|
||||
qse_size_t i;
|
||||
|
||||
/* check if there are too many chunks */
|
||||
if (fma->numcnks >= fma->maxcnks) return QSE_NULL;
|
||||
|
||||
/* allocate a chunk */
|
||||
cnk = (qse_fma_cnk_t*) QSE_MMGR_ALLOC (fma->mmgr,
|
||||
QSE_SIZEOF(*cnk) + fma->blksize * fma->maxblks);
|
||||
if (cnk == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/* weave the blocks in the chunk to the free block list */
|
||||
fma->freeblk = (qse_fma_blk_t*)(cnk + 1);
|
||||
blk = fma->freeblk;
|
||||
for (i = 1; i < fma->maxblks; i++)
|
||||
{
|
||||
blk->next = (qse_fma_blk_t*)((qse_byte_t*)blk + fma->blksize);
|
||||
blk = blk->next;
|
||||
}
|
||||
blk->next = QSE_NULL;
|
||||
|
||||
/* weave the chunk to the chunk list */
|
||||
cnk->next = fma->cnkhead;
|
||||
fma->cnkhead = cnk;
|
||||
fma->numcnks++;
|
||||
|
||||
return cnk;
|
||||
}
|
||||
|
||||
void* qse_fma_alloc (qse_fma_t* fma)
|
||||
{
|
||||
void* blk;
|
||||
|
||||
if ((blk = fma->freeblk) == QSE_NULL)
|
||||
{
|
||||
if (add_chunk (fma) == QSE_NULL) return QSE_NULL;
|
||||
blk = fma->freeblk;
|
||||
}
|
||||
fma->freeblk = fma->freeblk->next;
|
||||
return blk;
|
||||
}
|
||||
|
||||
void qse_fma_free (qse_fma_t* fma, void* blk)
|
||||
{
|
||||
((qse_fma_blk_t*)blk)->next = fma->freeblk;
|
||||
fma->freeblk = blk;
|
||||
}
|
||||
|
@ -142,7 +142,9 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
|
||||
qse_xma_blk_t* free;
|
||||
qse_size_t xfi;
|
||||
|
||||
/* round 'zonesize' to be the multiples of ALIGN */
|
||||
zonesize = ((zonesize + ALIGN - 1) / ALIGN) * ALIGN;
|
||||
|
||||
/* adjust 'zonesize' to be large enough to hold a single smallest block */
|
||||
if (zonesize < MINBLKLEN) zonesize = MINBLKLEN;
|
||||
|
||||
@ -162,10 +164,14 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
|
||||
xma->mmgr = mmgr;
|
||||
xma->bdec = szlog2(FIXED*ALIGN); /* precalculate the decrement value */
|
||||
|
||||
/* the entire chunk is a free block */
|
||||
/* at this point, the 'free' chunk is a only block available */
|
||||
|
||||
/* get the free block index */
|
||||
xfi = getxfi(xma,free->size);
|
||||
xma->xfree[xfi] = free; /* locate it at the right slot */
|
||||
xma->head = free; /* store it for furture reference */
|
||||
/* locate it into an apporopriate slot */
|
||||
xma->xfree[xfi] = free;
|
||||
/* let it be the head, which is natural with only a block */
|
||||
xma->head = free;
|
||||
|
||||
/* initialize some statistical variables */
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
@ -181,14 +187,22 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
|
||||
|
||||
void qse_xma_fini (qse_xma_t* xma)
|
||||
{
|
||||
/* the head must point to the free chunk allocated in init().
|
||||
* let's deallocate it */
|
||||
QSE_MMGR_FREE (xma->mmgr, xma->head);
|
||||
}
|
||||
|
||||
static QSE_INLINE void attach_to_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
|
||||
{
|
||||
qse_size_t xfi = getxfi(xma,b->size);
|
||||
/*
|
||||
* attach a block to a free list
|
||||
*/
|
||||
|
||||
b->f.prev = QSE_NULL;
|
||||
/* get the free list index for the block size */
|
||||
qse_size_t xfi = getxfi(xma,b->size);
|
||||
|
||||
/* let it be the head of the free list doubly-linked */
|
||||
b->f.prev = QSE_NULL;
|
||||
b->f.next = xma->xfree[xfi];
|
||||
if (xma->xfree[xfi]) xma->xfree[xfi]->f.prev = b;
|
||||
xma->xfree[xfi] = b;
|
||||
@ -196,22 +210,35 @@ static QSE_INLINE void attach_to_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
|
||||
|
||||
static QSE_INLINE void detach_from_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
|
||||
{
|
||||
/*
|
||||
* detach a block from a free list
|
||||
*/
|
||||
qse_xma_blk_t* p, * n;
|
||||
|
||||
/* alias the previous and the next with short variable names */
|
||||
p = b->f.prev;
|
||||
n = b->f.next;
|
||||
|
||||
if (p)
|
||||
{
|
||||
/* the previous item exists. let its 'next' pointer point to
|
||||
* the block's next item. */
|
||||
p->f.next = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the previous item does not exist. the block is the first
|
||||
* item in the free list. */
|
||||
|
||||
qse_size_t xfi = getxfi(xma,b->size);
|
||||
QSE_ASSERT (b == xma->xfree[xfi]);
|
||||
/* let's update the free list head */
|
||||
xma->xfree[xfi] = n;
|
||||
}
|
||||
if (n) n->f.prev = p;
|
||||
|
||||
/* let the 'prev' pointer of the block's next item point to the
|
||||
* block's previous item */
|
||||
if (n) n->f.prev = p;
|
||||
}
|
||||
|
||||
static qse_xma_blk_t* alloc_from_freelist (
|
||||
@ -363,22 +390,32 @@ static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t size)
|
||||
|
||||
if (size > blk->size)
|
||||
{
|
||||
/*
|
||||
* grow the current block
|
||||
*/
|
||||
|
||||
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 */
|
||||
/* check if the next adjacent block is available */
|
||||
if (!n || !n->avail || req > n->size) return QSE_NULL; /* no! */
|
||||
|
||||
/* let's merge the current block with the next block */
|
||||
detach_from_freelist (xma, n);
|
||||
|
||||
rem = (HDRSIZE + n->size) - req;
|
||||
if (rem >= MINBLKLEN)
|
||||
{
|
||||
/*
|
||||
* the remaining part of the next block is large enough
|
||||
* to hold a block. break the next block.
|
||||
*/
|
||||
|
||||
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;
|
||||
@ -404,6 +441,8 @@ static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t size)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the remaining part of the next block is negligible.
|
||||
* utilize the whole block by merging to the resizing block */
|
||||
blk->size += HDRSIZE + n->size;
|
||||
blk->b.next = n->b.next;
|
||||
if (n->b.next) n->b.next->b.prev = blk;
|
||||
@ -414,80 +453,13 @@ static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t 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)
|
||||
{
|
||||
/*
|
||||
* shrink the block
|
||||
*/
|
||||
|
||||
qse_size_t rem = blk->size - size;
|
||||
if (rem >= MINBLKLEN)
|
||||
{
|
||||
|
Reference in New Issue
Block a user