From 70ca33c7560c31c7546b38c79b2c941915513718 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 26 Aug 2010 07:15:40 +0000 Subject: [PATCH] added fixed-size block allocator --- qse/doc/page/cmn.doc | 3 +- qse/doc/page/main.doc | 10 +- qse/include/qse/cmn/Makefile.am | 2 +- qse/include/qse/cmn/Makefile.in | 12 +-- qse/include/qse/cmn/fma.h | 175 ++++++++++++++++++++++++++++++++ qse/include/qse/cmn/xma.h | 8 +- qse/lib/cmn/Makefile.am | 2 +- qse/lib/cmn/Makefile.in | 13 +-- qse/lib/cmn/fma.c | 139 +++++++++++++++++++++++++ qse/lib/cmn/xma.c | 132 ++++++++++-------------- qse/samples/cmn/Makefile.am | 3 +- qse/samples/cmn/Makefile.in | 27 +++-- qse/samples/cmn/fma.c | 70 +++++++++++++ 13 files changed, 486 insertions(+), 110 deletions(-) create mode 100644 qse/include/qse/cmn/fma.h create mode 100644 qse/lib/cmn/fma.c create mode 100644 qse/samples/cmn/fma.c diff --git a/qse/doc/page/cmn.doc b/qse/doc/page/cmn.doc index 40dec98a..4117d314 100644 --- a/qse/doc/page/cmn.doc +++ b/qse/doc/page/cmn.doc @@ -1,7 +1,8 @@ /** @page cmn COMMON FUNCTIONS @section xma MEMORY ALLOCATOR -QSE provides a memory allocator #qse_xma_t for private heap management. +- QSE provides a memory allocator #qse_xma_t for private heap management. +- QSE provides a fixed-size block memory allocator #qse_fma_t. @section rex REGULAR EXPRESSION QSE provides a regular expression processor #qse_rex_t. diff --git a/qse/doc/page/main.doc b/qse/doc/page/main.doc index 1ed85247..8a463682 100644 --- a/qse/doc/page/main.doc +++ b/qse/doc/page/main.doc @@ -92,9 +92,11 @@ foundation for other modules. Specialized functions and data structures are organized to dedicated modules. See relevant subpages for more information on each module. -- @subpage cmn "Common Functions" -- @subpage awk "AWK Interpreter" -- @subpage cut "CUT Text Cutter" -- @subpage sed "SED Stream Editor" +- @subpage cmn "Common Functions" + -# xma.h variable-size block memory allocator + -# fma.h fixed-size block memory allocator +- @subpage awk "AWK Interpreter" +- @subpage cut "CUT Text Cutter" +- @subpage sed "SED Stream Editor" */ diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index 62da1da9..72550f3d 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -1,7 +1,7 @@ pkgincludedir = $(includedir)/qse/cmn pkginclude_HEADERS = \ - mem.h xma.h chr.h str.h lda.h htb.h rbt.h \ + mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \ rex.h sll.h dll.h opt.h tio.h \ fio.h pio.h sio.h time.h misc.h main.h stdio.h diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index da0fcad3..2d0a093d 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -51,9 +51,9 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = -am__pkginclude_HEADERS_DIST = mem.h xma.h chr.h str.h lda.h htb.h \ - rbt.h rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h \ - misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp Mmged.hpp +am__pkginclude_HEADERS_DIST = mem.h xma.h fma.h chr.h str.h lda.h \ + htb.h rbt.h rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h \ + time.h misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp Mmged.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -220,9 +220,9 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkginclude_HEADERS = mem.h xma.h chr.h str.h lda.h htb.h rbt.h rex.h \ - sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h misc.h main.h \ - stdio.h $(am__append_1) +pkginclude_HEADERS = mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \ + rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h misc.h \ + main.h stdio.h $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/cmn/fma.h b/qse/include/qse/cmn/fma.h new file mode 100644 index 00000000..dc61b828 --- /dev/null +++ b/qse/include/qse/cmn/fma.h @@ -0,0 +1,175 @@ +/* + * $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 . + */ + +#ifndef _QSE_CMN_FMA_H_ +#define _QSE_CMN_FMA_H_ + +/** @file + * This file defines a fixed-size block memory allocator. As the block size + * is known in advance, it achieves block allocation with little overhead. + * + *
+ *  chunk head(cnkhead)   
+ *   |                                              chunk
+ *   |    +---------------------------------------------+
+ *   +--> |     |   f1     |   f2      |      |         |
+ *        +--|---------^------|----^--------------------+
+ *           |         |      |    |
+ *           |         +------+    +---+    +--------------+   chunk
+ *           |                         |    |              |
+ *           |       +-----------------|----V--------------|-------+
+ *           +--->   |     |         |   f3    |         |  f4     |
+ *                   +---------------------------------------^-----+
+ *                                                           |
+ *                                           free block head (freeblk)
+ * 
+ * + * The diagram above assumes that f1, f2, f3, and f4 are free blocks. + * The chaining order depends on the allocation and deallocation order. + * + * See #qse_fma_t for more information. Use #qse_xma_t for variable-size block + * allocation. + */ + +#include +#include + +/** @struct qse_fma_cnk_t + * The qse_fma_cnk_t type defines a memory chunk header to hold memory blocks. + * The chunks added are maintained in a singly-linked list + */ +typedef struct qse_fma_cnk_t qse_fma_cnk_t; +struct qse_fma_cnk_t +{ + qse_fma_cnk_t* next; /**< point to the next chunk */ +}; + +/** @struct qse_fma_blk_t + * The qse_fma_blk_t type defines a memory block header to weave free blocks + * into a singly-linked list. + */ +typedef struct qse_fma_blk_t qse_fma_blk_t; +struct qse_fma_blk_t +{ + qse_fma_blk_t* next; /**< point to the next block */ +}; + +/** @struct qse_fma_t + * The qse_fma_t type defines a fixed-size block memory allocator. + * See the example below. Note that it omits error handling. + * @code + * qse_fma_t* fma; + * int* ptr1, * ptr2; + * + * // create a memory allocator for integer blocks up to 50. + * fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5); + * + * // allocate two integer blocks + * ptr1 = (int*) qse_fma_alloc (fma); + * ptr2 = (int*) qse_fma_alloc (fma); + * + * *ptr1 = 20; *ptr2 = 99; + * + * // free the two blocks. + * qse_fma_free (fma, ptr1); + * qse_fma_free (fma, ptr2); + * + * // destroy the memory allocator + * qse_fma_close (fma); + * @endcode + */ +typedef struct qse_fma_t qse_fma_t; +struct qse_fma_t +{ + QSE_DEFINE_COMMON_FIELDS (fma) + + qse_size_t blksize; /**< block size */ + qse_size_t maxblks; /**< maximum blocks in a chunk */ + qse_size_t maxcnks; /**< maximum chunks */ + + qse_size_t numcnks; /**< current numbers of chunks */ + qse_fma_cnk_t* cnkhead; /**< point to the first chunk added */ + qse_fma_blk_t* freeblk; /**< point to the first free block */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +QSE_DEFINE_COMMON_FUNCTIONS (fma) + +/** + * The qse_fma_open() function creates a memory allocator with an outer + * memory manager. + */ +qse_fma_t* qse_fma_open ( + qse_mmgr_t* mmgr, /**< outer memory manager */ + qse_size_t xtnsize, /**< extension size in bytes */ + qse_size_t blksize, /**< block size in bytes */ + qse_size_t maxblks, /**< maximum numbers of blocks in a chunk */ + qse_size_t maxcnks /**< maximum numbers of chunks */ +); + +/** + * The qse_fma_close() function destroys an memory allocator. + */ +void qse_fma_close ( + qse_fma_t* fma /**< memory allocator */ +); + +/** + * The qse_fma_init() function initializes an memory allocator. + */ +qse_fma_t* qse_fma_init ( + qse_fma_t* fma, /**< memory allocator */ + qse_mmgr_t* mmgr, /**< outer memory manager */ + qse_size_t blksize, /**< block size in bytes */ + qse_size_t maxblks, /**< maximum numbers of blocks in a chunk */ + qse_size_t maxcnks /**< maximum numbers of chunks */ +); + +/** + * The qse_fma_fini() function finalizes an memory allocator. + */ +void qse_fma_fini ( + qse_fma_t* fma /**< memory allocator */ +); + +/** + * The qse_fma_alloc() function allocates a block. + * @return block pointer on success, QSE_NULL on failure + */ +void* qse_fma_alloc ( + qse_fma_t* fma /**< memory allocator */ +); + +/** + * The qse_fma_alloc() function deallocates a block. + */ +void qse_fma_free ( + qse_fma_t* fma, /**< memory allocator */ + void* blk /**< memory block to free */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/xma.h b/qse/include/qse/cmn/xma.h index 307a2cfa..f9360e67 100644 --- a/qse/include/qse/cmn/xma.h +++ b/qse/include/qse/cmn/xma.h @@ -23,6 +23,11 @@ /** @file * This file defines an extravagant memory allocator. Why? It may be so. + * The memory allocator allows you to maintain memory blocks from a + * larger memory chunk allocated with an outer memory allocator. + * Typically, an outer memory allocator is a standard memory allocator + * like malloc(). You can isolate memory blocks into a particular chunk. + * See #qse_xma_t for an example. */ #include #include @@ -173,7 +178,8 @@ void qse_xma_free ( /** * The qse_xma_dump() function dumps the contents of the memory zone - * with the output function @a printf provided. + * with the output function @a printf provided. The debug build shows + * more statistical counters. */ void qse_xma_dump ( qse_xma_t* xma, /**< memory allocator */ diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index 64bff876..65cda218 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -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 \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 316fe13f..86f1cbd4 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -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@ diff --git a/qse/lib/cmn/fma.c b/qse/lib/cmn/fma.c new file mode 100644 index 00000000..6e5c7eb1 --- /dev/null +++ b/qse/lib/cmn/fma.c @@ -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 . + */ + +#include +#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; +} + diff --git a/qse/lib/cmn/xma.c b/qse/lib/cmn/xma.c index 97fe5217..c05594b8 100644 --- a/qse/lib/cmn/xma.c +++ b/qse/lib/cmn/xma.c @@ -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) { diff --git a/qse/samples/cmn/Makefile.am b/qse/samples/cmn/Makefile.am index 70eeca05..a188f22e 100644 --- a/qse/samples/cmn/Makefile.am +++ b/qse/samples/cmn/Makefile.am @@ -1,11 +1,12 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG -bin_PROGRAMS = xma chr str sll lda htb rbt fio pio sio time main rex01 +bin_PROGRAMS = xma fma chr str sll lda htb rbt fio pio sio time main rex01 LDFLAGS = -L../../lib/cmn LDADD = -lqsecmn xma_SOURCES = xma.c +fma_SOURCES = fma.c chr_SOURCES = chr.c str_SOURCES = str.c sll_SOURCES = sll.c diff --git a/qse/samples/cmn/Makefile.in b/qse/samples/cmn/Makefile.in index 20ec9c5c..b0238b5b 100644 --- a/qse/samples/cmn/Makefile.in +++ b/qse/samples/cmn/Makefile.in @@ -34,10 +34,10 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -bin_PROGRAMS = xma$(EXEEXT) chr$(EXEEXT) str$(EXEEXT) sll$(EXEEXT) \ - lda$(EXEEXT) htb$(EXEEXT) rbt$(EXEEXT) fio$(EXEEXT) \ - pio$(EXEEXT) sio$(EXEEXT) time$(EXEEXT) main$(EXEEXT) \ - rex01$(EXEEXT) +bin_PROGRAMS = xma$(EXEEXT) fma$(EXEEXT) chr$(EXEEXT) str$(EXEEXT) \ + sll$(EXEEXT) lda$(EXEEXT) htb$(EXEEXT) rbt$(EXEEXT) \ + fio$(EXEEXT) pio$(EXEEXT) sio$(EXEEXT) time$(EXEEXT) \ + main$(EXEEXT) rex01$(EXEEXT) subdir = samples/cmn DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -62,6 +62,10 @@ am_fio_OBJECTS = fio.$(OBJEXT) fio_OBJECTS = $(am_fio_OBJECTS) fio_LDADD = $(LDADD) fio_DEPENDENCIES = +am_fma_OBJECTS = fma.$(OBJEXT) +fma_OBJECTS = $(am_fma_OBJECTS) +fma_LDADD = $(LDADD) +fma_DEPENDENCIES = am_htb_OBJECTS = htb.$(OBJEXT) htb_OBJECTS = $(am_htb_OBJECTS) htb_LDADD = $(LDADD) @@ -119,14 +123,14 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(htb_SOURCES) $(lda_SOURCES) \ - $(main_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) $(rex01_SOURCES) \ - $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) $(time_SOURCES) \ - $(xma_SOURCES) -DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(htb_SOURCES) \ +SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(fma_SOURCES) $(htb_SOURCES) \ $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) \ $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) \ $(time_SOURCES) $(xma_SOURCES) +DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(fma_SOURCES) \ + $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) \ + $(rbt_SOURCES) $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) \ + $(str_SOURCES) $(time_SOURCES) $(xma_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -272,6 +276,7 @@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG LDADD = -lqsecmn xma_SOURCES = xma.c +fma_SOURCES = fma.c chr_SOURCES = chr.c str_SOURCES = str.c sll_SOURCES = sll.c @@ -367,6 +372,9 @@ chr$(EXEEXT): $(chr_OBJECTS) $(chr_DEPENDENCIES) fio$(EXEEXT): $(fio_OBJECTS) $(fio_DEPENDENCIES) @rm -f fio$(EXEEXT) $(LINK) $(fio_OBJECTS) $(fio_LDADD) $(LIBS) +fma$(EXEEXT): $(fma_OBJECTS) $(fma_DEPENDENCIES) + @rm -f fma$(EXEEXT) + $(LINK) $(fma_OBJECTS) $(fma_LDADD) $(LIBS) htb$(EXEEXT): $(htb_OBJECTS) $(htb_DEPENDENCIES) @rm -f htb$(EXEEXT) $(LINK) $(htb_OBJECTS) $(htb_LDADD) $(LIBS) @@ -409,6 +417,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ diff --git a/qse/samples/cmn/fma.c b/qse/samples/cmn/fma.c new file mode 100644 index 00000000..58c44562 --- /dev/null +++ b/qse/samples/cmn/fma.c @@ -0,0 +1,70 @@ +#include +#include + +#define R(f) \ + do { \ + qse_printf (QSE_T("== %s ==\n"), QSE_T(#f)); \ + if (f() == -1) return -1; \ + } while (0) + +static int test1 () +{ + int i; + int* ptr[100]; + + qse_fma_t* fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5); + if (fma == QSE_NULL) + { + qse_printf (QSE_T("cannot open fma\n")); + return -1; + } + + for (i = 0; i < 100; i++) + { + ptr[i] = qse_fma_alloc (fma); + if (ptr[i]) + { + qse_printf (QSE_T("%d %p\n"), i, ptr[i]); + *(ptr[i]) = i; + } + else qse_printf (QSE_T("%d FAIL\n"), i); + } + + for (i = 0; i < 30; i+=2) + { + if (ptr[i]) + { + qse_fma_free (fma, ptr[i]); + ptr[i] = QSE_NULL; + } + } + + for (i = 0; i < 100; i++) + { + if (ptr[i]) + { + qse_fma_free (fma, ptr[i]); + ptr[i] = QSE_NULL; + } + } + + for (i = 0; i < 100; i++) + { + ptr[i] = qse_fma_alloc (fma); + if (ptr[i]) + { + qse_printf (QSE_T("%d %p\n"), i, ptr[i]); + *(ptr[i]) = i; + } + else qse_printf (QSE_T("%d FAIL\n"), i); + } + + qse_fma_close (fma); + return 0; +} + +int main () +{ + R (test1); + return 0; +}