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