adding a new memory manager
This commit is contained in:
		
							
								
								
									
										231
									
								
								moo/lib/moo-xma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								moo/lib/moo-xma.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,231 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2014-2019 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
    are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
       documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
			
		||||
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _MOO_XMA_H_
 | 
			
		||||
#define _MOO_XMA_H_
 | 
			
		||||
 | 
			
		||||
/** @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 the example below. Note it omits error handling.
 | 
			
		||||
 *
 | 
			
		||||
 * @code
 | 
			
		||||
 * #include <qse/cmn/xma.h>
 | 
			
		||||
 * #include <qse/cmn/stdio.h>
 | 
			
		||||
 * int main ()
 | 
			
		||||
 * {
 | 
			
		||||
 *   moo_xma_t* xma;
 | 
			
		||||
 *   void* ptr1, * ptr2;
 | 
			
		||||
 *
 | 
			
		||||
 *   // create a new memory allocator obtaining a 100K byte zone 
 | 
			
		||||
 *   // with the default memory allocator
 | 
			
		||||
 *   xma = moo_xma_open (MOO_NULL, 0, 100000L); 
 | 
			
		||||
 *
 | 
			
		||||
 *   ptr1 = moo_xma_alloc (xma, 5000); // allocate a 5K block from the zone
 | 
			
		||||
 *   ptr2 = moo_xma_alloc (xma, 1000); // allocate a 1K block from the zone
 | 
			
		||||
 *   ptr1 = moo_xma_realloc (xma, ptr1, 6000); // resize the 5K block to 6K.
 | 
			
		||||
 *
 | 
			
		||||
 *   moo_xma_dump (xma, moo_fprintf, MOO_STDOUT); // dump memory blocks 
 | 
			
		||||
 *
 | 
			
		||||
 *   // the following two lines are not actually needed as the allocator
 | 
			
		||||
 *   // is closed after them.
 | 
			
		||||
 *   moo_xma_free (xma, ptr2); // dispose of the 1K block
 | 
			
		||||
 *   moo_xma_free (xma, ptr1); // dispose of the 6K block
 | 
			
		||||
 *
 | 
			
		||||
 *   moo_xma_close (xma); //  destroy the memory allocator
 | 
			
		||||
 *   return 0;
 | 
			
		||||
 * }
 | 
			
		||||
 * @endcode
 | 
			
		||||
 */
 | 
			
		||||
#include <moo-cmn.h>
 | 
			
		||||
 | 
			
		||||
#ifdef MOO_BUILD_DEBUG
 | 
			
		||||
#	define MOO_XMA_ENABLE_STAT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @struct moo_xma_t
 | 
			
		||||
 * The moo_xma_t type defines a simple memory allocator over a memory zone.
 | 
			
		||||
 * It can obtain a relatively large zone of memory and manage it.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct moo_xma_t moo_xma_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_blk_t type defines a memory block allocated.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct moo_xma_blk_t moo_xma_blk_t;
 | 
			
		||||
 | 
			
		||||
#define MOO_XMA_FIXED 32
 | 
			
		||||
#define MOO_XMA_SIZE_BITS ((MOO_SIZEOF_OOW_T*8)-1)
 | 
			
		||||
 | 
			
		||||
struct moo_xma_t
 | 
			
		||||
{
 | 
			
		||||
	moo_mmgr_t* _mmgr;
 | 
			
		||||
 | 
			
		||||
	/** pointer to the first memory block */
 | 
			
		||||
	moo_xma_blk_t* head; 
 | 
			
		||||
 | 
			
		||||
	/** pointer array to free memory blocks */
 | 
			
		||||
	moo_xma_blk_t* xfree[MOO_XMA_FIXED + MOO_XMA_SIZE_BITS + 1]; 
 | 
			
		||||
 | 
			
		||||
	/** pre-computed value for fast xfree index calculation */
 | 
			
		||||
	moo_oow_t     bdec;
 | 
			
		||||
 | 
			
		||||
#ifdef MOO_XMA_ENABLE_STAT
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		moo_oow_t total;
 | 
			
		||||
		moo_oow_t alloc;
 | 
			
		||||
		moo_oow_t avail;
 | 
			
		||||
		moo_oow_t nused;
 | 
			
		||||
		moo_oow_t nfree;
 | 
			
		||||
	} stat;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_dumper_t type defines a printf-like output function
 | 
			
		||||
 * for moo_xma_dump().
 | 
			
		||||
 */
 | 
			
		||||
typedef int (*moo_xma_dumper_t) (
 | 
			
		||||
	void*            ctx,
 | 
			
		||||
	const moo_bch_t* fmt,
 | 
			
		||||
	...
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_open() function creates a memory allocator. It obtains a memory
 | 
			
		||||
 * zone of the @a zonesize bytes with the memory manager @a mmgr. It also makes
 | 
			
		||||
 * available the extension area of the @a xtnsize bytes that you can get the
 | 
			
		||||
 * pointer to with moo_xma_getxtn().
 | 
			
		||||
 *
 | 
			
		||||
 * @return pointer to a memory allocator on success, #MOO_NULL on failure
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT moo_xma_t* moo_xma_open (
 | 
			
		||||
	moo_mmgr_t* mmgr,    /**< memory manager */
 | 
			
		||||
	moo_oow_t  xtnsize, /**< extension size in bytes */
 | 
			
		||||
	moo_oow_t  zonesize /**< zone size in bytes */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_close() function destroys a memory allocator. It also frees
 | 
			
		||||
 * the memory zone obtained, which invalidates the memory blocks within 
 | 
			
		||||
 * the zone. Call this function to destroy a memory allocator created with
 | 
			
		||||
 * moo_xma_open().
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT void moo_xma_close (
 | 
			
		||||
	moo_xma_t* xma /**< memory allocator */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_HAVE_INLINE)
 | 
			
		||||
static MOO_INLINE moo_mmgr_t* moo_xma_getmmgr (moo_xma_t* xma) { return xma->_mmgr; }
 | 
			
		||||
#else
 | 
			
		||||
#	define moo_xma_getmmgr(xma) (((moo_xma_t*)(xma))->_mmgr)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_HAVE_INLINE)
 | 
			
		||||
static MOO_INLINE void* moo_xma_getxtn (moo_xma_t* xma) { return (void*)(xma + 1); }
 | 
			
		||||
#else
 | 
			
		||||
#define moo_xma_getxtn(xma) ((void*)((moo_xma_t*)(xma) + 1))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_init() initializes a memory allocator. If you have the moo_xma_t
 | 
			
		||||
 * structure statically declared or already allocated, you may pass the pointer
 | 
			
		||||
 * to this function instead of calling moo_xma_open(). It obtains a memory zone
 | 
			
		||||
 * of @a zonesize bytes with the memory manager @a mmgr. Unlike moo_xma_open(),
 | 
			
		||||
 * it does not accept the extension size, thus not creating an extention area.
 | 
			
		||||
 * @return 0 on success, -1 on failure
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT int moo_xma_init (
 | 
			
		||||
	moo_xma_t*  xma,     /**< memory allocator */
 | 
			
		||||
	moo_mmgr_t* mmgr,    /**< memory manager */
 | 
			
		||||
	moo_oow_t  zonesize /**< zone size in bytes */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_fini() function finalizes a memory allocator. Call this 
 | 
			
		||||
 * function to finalize a memory allocator initialized with moo_xma_init().
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT void moo_xma_fini (
 | 
			
		||||
	moo_xma_t* xma /**< memory allocator */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_alloc() function allocates @a size bytes.
 | 
			
		||||
 * @return pointer to a memory block on success, #MOO_NULL on failure
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT void* moo_xma_alloc (
 | 
			
		||||
	moo_xma_t* xma, /**< memory allocator */
 | 
			
		||||
	moo_oow_t size /**< size in bytes */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MOO_EXPORT void* moo_xma_calloc (
 | 
			
		||||
	moo_xma_t* xma,
 | 
			
		||||
	moo_oow_t size
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_alloc() function resizes the memory block @a b to @a size bytes.
 | 
			
		||||
 * @return pointer to a resized memory block on success, #MOO_NULL on failure
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT void* moo_xma_realloc (
 | 
			
		||||
	moo_xma_t* xma,  /**< memory allocator */
 | 
			
		||||
	void*      b,    /**< memory block */
 | 
			
		||||
	moo_oow_t size  /**< new size in bytes */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_alloc() function frees the memory block @a b.
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT void moo_xma_free (
 | 
			
		||||
	moo_xma_t* xma, /**< memory allocator */
 | 
			
		||||
	void*      b    /**< memory block */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The moo_xma_dump() function dumps the contents of the memory zone
 | 
			
		||||
 * with the output function @a dumper provided. The debug build shows
 | 
			
		||||
 * more statistical counters.
 | 
			
		||||
 */
 | 
			
		||||
MOO_EXPORT void moo_xma_dump (
 | 
			
		||||
	moo_xma_t*       xma,    /**< memory allocator */
 | 
			
		||||
	moo_xma_dumper_t dumper, /**< output function */
 | 
			
		||||
	void*            ctx     /**< first parameter to output function */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										764
									
								
								moo/lib/xma.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										764
									
								
								moo/lib/xma.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,764 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2014-2019 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
    are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
       documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
			
		||||
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <moo-xma.h>
 | 
			
		||||
#include "moo-prv.h"
 | 
			
		||||
#include <assert.h> /* TODO: replace assert() with builtin substition */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define ALIGN MOO_SIZEOF(moo_oow_t) /* this must be a power of 2 */
 | 
			
		||||
#define HDRSIZE MOO_SIZEOF(moo_xma_blk_t)
 | 
			
		||||
#define MINBLKLEN (HDRSIZE + ALIGN)
 | 
			
		||||
 | 
			
		||||
#define SYS_TO_USR(_) (((moo_xma_blk_t*)_) + 1)
 | 
			
		||||
#define USR_TO_SYS(_) (((moo_xma_blk_t*)_) - 1)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * the xfree array is divided into three region
 | 
			
		||||
 * 0 ....................... FIXED ......................... XFIMAX-1 ... XFIMAX
 | 
			
		||||
 * |  small fixed-size chains |     large  chains                | huge chain |
 | 
			
		||||
 */
 | 
			
		||||
#define FIXED MOO_XMA_FIXED
 | 
			
		||||
#define XFIMAX(xma) (MOO_COUNTOF(xma->xfree)-1)
 | 
			
		||||
 | 
			
		||||
struct moo_xma_blk_t 
 | 
			
		||||
{
 | 
			
		||||
	moo_oow_t avail: 1;
 | 
			
		||||
	moo_oow_t size: MOO_XMA_SIZE_BITS;/**< block size */
 | 
			
		||||
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		moo_xma_blk_t* prev; /**< link to the previous free block */
 | 
			
		||||
		moo_xma_blk_t* next; /**< link to the next free block */
 | 
			
		||||
	} f;
 | 
			
		||||
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		moo_xma_blk_t* prev; /**< link to the previous adjacent block */
 | 
			
		||||
		moo_xma_blk_t* next; /**< link to the next adjacent block */
 | 
			
		||||
	} b;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static MOO_INLINE moo_oow_t szlog2 (moo_oow_t n) 
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * 2**x = n;
 | 
			
		||||
	 * x = log2(n);
 | 
			
		||||
	 * -------------------------------------------
 | 
			
		||||
	 * 	unsigned int x = 0;
 | 
			
		||||
	 * 	while((n >> x) > 1) ++x;
 | 
			
		||||
	 * 	return x;
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
#define BITS (MOO_SIZEOF_OOW_T * 8)
 | 
			
		||||
	int x = BITS - 1;
 | 
			
		||||
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 128
 | 
			
		||||
#	error moo_oow_t too large. unsupported platform
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 64
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-128))) == 0) { x -= 256; n <<= 256; }
 | 
			
		||||
#endif
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 32
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-128))) == 0) { x -= 128; n <<= 128; }
 | 
			
		||||
#endif
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 16
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-64))) == 0) { x -= 64; n <<= 64; }
 | 
			
		||||
#endif
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 8
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-32))) == 0) { x -= 32; n <<= 32; }
 | 
			
		||||
#endif
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 4 
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-16))) == 0) { x -= 16; n <<= 16; }
 | 
			
		||||
#endif
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 2
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-8))) == 0) { x -= 8; n <<= 8; }
 | 
			
		||||
#endif
 | 
			
		||||
#if MOO_SIZEOF_OOW_T >= 1
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-4))) == 0) { x -= 4; n <<= 4; }
 | 
			
		||||
#endif
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-2))) == 0) { x -= 2; n <<= 2; }
 | 
			
		||||
	if ((n & (~(moo_oow_t)0 << (BITS-1))) == 0) { x -= 1; }
 | 
			
		||||
 | 
			
		||||
	return x;
 | 
			
		||||
#undef BITS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MOO_INLINE moo_oow_t getxfi (moo_xma_t* xma, moo_oow_t size) 
 | 
			
		||||
{
 | 
			
		||||
	moo_oow_t xfi = ((size) / ALIGN) - 1;
 | 
			
		||||
	if (xfi >= FIXED) xfi = szlog2(size) - (xma)->bdec + FIXED;
 | 
			
		||||
	if (xfi > XFIMAX(xma)) xfi = XFIMAX(xma);
 | 
			
		||||
	return xfi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
moo_xma_t* moo_xma_open (moo_mmgr_t* mmgr, moo_oow_t xtnsize, moo_oow_t zonesize)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_t* xma;
 | 
			
		||||
 | 
			
		||||
	xma = (moo_xma_t*) MOO_MMGR_ALLOC (mmgr, MOO_SIZEOF(*xma) + xtnsize);
 | 
			
		||||
	if (xma == MOO_NULL) return MOO_NULL;
 | 
			
		||||
 | 
			
		||||
	if (moo_xma_init (xma, mmgr, zonesize) <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		MOO_MMGR_FREE (mmgr, xma);
 | 
			
		||||
		return MOO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MOO_MEMSET (xma + 1, 0, xtnsize);
 | 
			
		||||
	return xma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void moo_xma_close (moo_xma_t* xma)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_fini (xma);
 | 
			
		||||
	MOO_MMGR_FREE (xma->_mmgr, xma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int moo_xma_init (moo_xma_t* xma, moo_mmgr_t* mmgr, moo_oow_t zonesize)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_blk_t* free;
 | 
			
		||||
	moo_oow_t xfi;
 | 
			
		||||
 | 
			
		||||
	/* round 'zonesize' to be the multiples of ALIGN */
 | 
			
		||||
	zonesize = MOO_ALIGN_POW2(zonesize, ALIGN);
 | 
			
		||||
 | 
			
		||||
	/* adjust 'zonesize' to be large enough to hold a single smallest block */
 | 
			
		||||
	if (zonesize < MINBLKLEN) zonesize = MINBLKLEN;
 | 
			
		||||
 | 
			
		||||
	/* allocate a memory chunk to use for actual memory allocation */
 | 
			
		||||
	free = MOO_MMGR_ALLOC(mmgr, zonesize);
 | 
			
		||||
	if (free == MOO_NULL) return -1;
 | 
			
		||||
	
 | 
			
		||||
	/* initialize the header part of the free chunk */
 | 
			
		||||
	free->avail = 1;
 | 
			
		||||
	free->size = zonesize - HDRSIZE; /* size excluding the block header */
 | 
			
		||||
	free->f.prev = MOO_NULL;
 | 
			
		||||
	free->f.next = MOO_NULL;
 | 
			
		||||
	free->b.next = MOO_NULL;
 | 
			
		||||
	free->b.prev = MOO_NULL;
 | 
			
		||||
 | 
			
		||||
	MOO_MEMSET (xma, 0, MOO_SIZEOF(*xma));
 | 
			
		||||
	xma->_mmgr = mmgr;
 | 
			
		||||
	xma->bdec = szlog2(FIXED * ALIGN); /* precalculate the decrement value */
 | 
			
		||||
 | 
			
		||||
	/* at this point, the 'free' chunk is a only block available */
 | 
			
		||||
 | 
			
		||||
	/* get the free block index */
 | 
			
		||||
	xfi = getxfi(xma, free->size);
 | 
			
		||||
	/* 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 */
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	xma->stat.total = zonesize;
 | 
			
		||||
	xma->stat.alloc = 0;
 | 
			
		||||
	xma->stat.avail = zonesize - HDRSIZE;
 | 
			
		||||
	xma->stat.nfree = 1;
 | 
			
		||||
	xma->stat.nused = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void moo_xma_fini (moo_xma_t* xma)
 | 
			
		||||
{
 | 
			
		||||
	/* the head must point to the free chunk allocated in init().
 | 
			
		||||
	 * let's deallocate it */
 | 
			
		||||
	MOO_MMGR_FREE (xma->_mmgr, xma->head);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MOO_INLINE void attach_to_freelist (moo_xma_t* xma, moo_xma_blk_t* b)
 | 
			
		||||
{
 | 
			
		||||
	/* 
 | 
			
		||||
	 * attach a block to a free list 
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* get the free list index for the block size */
 | 
			
		||||
	moo_oow_t xfi = getxfi(xma, b->size); 
 | 
			
		||||
 | 
			
		||||
	/* let it be the head of the free list doubly-linked */
 | 
			
		||||
	b->f.prev = MOO_NULL; 
 | 
			
		||||
	b->f.next = xma->xfree[xfi];
 | 
			
		||||
	if (xma->xfree[xfi]) xma->xfree[xfi]->f.prev = b;
 | 
			
		||||
	xma->xfree[xfi] = b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MOO_INLINE void detach_from_freelist (moo_xma_t* xma, moo_xma_blk_t* b)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
 	 * detach a block from a free list 
 | 
			
		||||
 	 */
 | 
			
		||||
	moo_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. */
 | 
			
		||||
 | 
			
		||||
		moo_oow_t xfi = getxfi(xma, b->size);
 | 
			
		||||
		assert (b == xma->xfree[xfi]);
 | 
			
		||||
		/* let's update the free list head */
 | 
			
		||||
		xma->xfree[xfi] = n;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* let the 'prev' pointer of the block's next item point to the 
 | 
			
		||||
	 * block's previous item */
 | 
			
		||||
	if (n) n->f.prev = p; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static moo_xma_blk_t* alloc_from_freelist (
 | 
			
		||||
	moo_xma_t* xma, moo_oow_t xfi, moo_oow_t size)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_blk_t* free;
 | 
			
		||||
 | 
			
		||||
	for (free = xma->xfree[xfi]; free; free = free->f.next)
 | 
			
		||||
	{
 | 
			
		||||
		if (free->size >= size)
 | 
			
		||||
		{
 | 
			
		||||
			moo_oow_t rem;
 | 
			
		||||
 | 
			
		||||
			detach_from_freelist (xma, free);
 | 
			
		||||
 | 
			
		||||
			rem = free->size - size;
 | 
			
		||||
			if (rem >= MINBLKLEN)
 | 
			
		||||
			{
 | 
			
		||||
				moo_xma_blk_t* tmp;
 | 
			
		||||
 | 
			
		||||
				/* the remaining part is large enough to hold 
 | 
			
		||||
				 * another block. let's split it 
 | 
			
		||||
				 */
 | 
			
		||||
 | 
			
		||||
				/* shrink the size of the 'free' block */
 | 
			
		||||
				free->size = size;
 | 
			
		||||
 | 
			
		||||
				/* let 'tmp' point to the remaining part */
 | 
			
		||||
				tmp = (moo_xma_blk_t*)(((moo_uint8_t*)(free + 1)) + size);
 | 
			
		||||
 | 
			
		||||
				/* initialize some fields */
 | 
			
		||||
				tmp->avail = 1;
 | 
			
		||||
				tmp->size = rem - HDRSIZE;
 | 
			
		||||
 | 
			
		||||
				/* link 'tmp' to the block list */
 | 
			
		||||
				tmp->b.next = free->b.next;
 | 
			
		||||
				tmp->b.prev = free;
 | 
			
		||||
				if (free->b.next) free->b.next->b.prev = tmp;
 | 
			
		||||
				free->b.next = tmp;
 | 
			
		||||
 | 
			
		||||
				/* add the remaining part to the free list */
 | 
			
		||||
				attach_to_freelist (xma, tmp);
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
				xma->stat.avail -= HDRSIZE;
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* decrement the number of free blocks as the current
 | 
			
		||||
				 * block is allocated as a whole without being split */
 | 
			
		||||
				xma->stat.nfree--;
 | 
			
		||||
			}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			free->avail = 0;
 | 
			
		||||
			/*
 | 
			
		||||
			free->f.next = MOO_NULL;
 | 
			
		||||
			free->f.prev = MOO_NULL;
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
			xma->stat.nused++;
 | 
			
		||||
			xma->stat.alloc += free->size;
 | 
			
		||||
			xma->stat.avail -= free->size;
 | 
			
		||||
#endif
 | 
			
		||||
			return free;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return MOO_NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* moo_xma_alloc (moo_xma_t* xma, moo_oow_t size)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_blk_t* free;
 | 
			
		||||
	moo_oow_t xfi;
 | 
			
		||||
 | 
			
		||||
	if (size <= 0) size = 1;
 | 
			
		||||
 | 
			
		||||
	/* round up 'size' to the multiples of ALIGN */
 | 
			
		||||
	size = MOO_ALIGN_POW2(size, ALIGN);
 | 
			
		||||
 | 
			
		||||
	assert (size >= ALIGN);
 | 
			
		||||
	xfi = getxfi(xma, size);
 | 
			
		||||
 | 
			
		||||
	/*if (xfi < XFIMAX(xma) && xma->xfree[xfi])*/
 | 
			
		||||
	if (xfi < FIXED && xma->xfree[xfi])
 | 
			
		||||
	{
 | 
			
		||||
		/* try the best fit */
 | 
			
		||||
		free = xma->xfree[xfi];
 | 
			
		||||
 | 
			
		||||
		assert (free->avail != 0);
 | 
			
		||||
		assert (free->size == size);
 | 
			
		||||
 | 
			
		||||
		detach_from_freelist (xma, free);
 | 
			
		||||
		free->avail = 0;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
		xma->stat.nfree--;
 | 
			
		||||
		xma->stat.nused++;
 | 
			
		||||
		xma->stat.alloc += free->size;
 | 
			
		||||
		xma->stat.avail -= free->size;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	else if (xfi == XFIMAX(xma))
 | 
			
		||||
	{
 | 
			
		||||
		/* huge block */
 | 
			
		||||
		free = alloc_from_freelist (xma, XFIMAX(xma), size);
 | 
			
		||||
		if (free == MOO_NULL) return MOO_NULL;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (xfi >= FIXED)
 | 
			
		||||
		{
 | 
			
		||||
			/* get the block from its own large chain */
 | 
			
		||||
			free = alloc_from_freelist (xma, xfi, size);
 | 
			
		||||
			if (free == MOO_NULL)
 | 
			
		||||
			{
 | 
			
		||||
				/* borrow a large block from the huge block chain */
 | 
			
		||||
				free = alloc_from_freelist (xma, XFIMAX(xma), size);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* borrow a small block from the huge block chain */
 | 
			
		||||
			free = alloc_from_freelist (xma, XFIMAX(xma), size);
 | 
			
		||||
			if (free == MOO_NULL) xfi = FIXED - 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (free == MOO_NULL)
 | 
			
		||||
		{
 | 
			
		||||
			/* try each large block chain left */
 | 
			
		||||
			for (++xfi; xfi < XFIMAX(xma) - 1; xfi++)
 | 
			
		||||
			{
 | 
			
		||||
				free = alloc_from_freelist (xma, xfi, size);
 | 
			
		||||
				if (free) break;
 | 
			
		||||
			}
 | 
			
		||||
			if (free == MOO_NULL) return MOO_NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return SYS_TO_USR(free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void* _realloc_merge (moo_xma_t* xma, void* b, moo_oow_t size)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_blk_t* blk = USR_TO_SYS(b);
 | 
			
		||||
 | 
			
		||||
	/* rounds up 'size' to be multiples of ALIGN */ 
 | 
			
		||||
	size = MOO_ALIGN_POW2 (size, ALIGN);
 | 
			
		||||
 | 
			
		||||
	if (size > blk->size)
 | 
			
		||||
	{
 | 
			
		||||
		/* 
 | 
			
		||||
		 * grow the current block
 | 
			
		||||
		 */
 | 
			
		||||
		moo_oow_t req;
 | 
			
		||||
		moo_xma_blk_t* n;
 | 
			
		||||
		moo_oow_t rem;
 | 
			
		||||
		
 | 
			
		||||
		req = size - blk->size;
 | 
			
		||||
 | 
			
		||||
		n = blk->b.next;
 | 
			
		||||
 | 
			
		||||
		/* check if the next adjacent block is available */
 | 
			
		||||
		if (!n || !n->avail || req > n->size) return MOO_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.
 | 
			
		||||
			 */
 | 
			
		||||
 | 
			
		||||
			moo_xma_blk_t* tmp;
 | 
			
		||||
 | 
			
		||||
			/* store n->b.next in case 'tmp' begins somewhere 
 | 
			
		||||
			 * in the header part of n */
 | 
			
		||||
			moo_xma_blk_t* nn = n->b.next; 
 | 
			
		||||
 | 
			
		||||
			tmp = (moo_xma_blk_t*)(((moo_uint8_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;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
			xma->stat.alloc += req;
 | 
			
		||||
			xma->stat.avail -= req; /* req + HDRSIZE(tmp) - HDRSIZE(n) */
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
			xma->stat.nfree--;
 | 
			
		||||
			xma->stat.alloc += HDRSIZE + n->size;
 | 
			
		||||
			xma->stat.avail -= n->size;
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (size < blk->size)
 | 
			
		||||
	{
 | 
			
		||||
		/* 
 | 
			
		||||
		 * shrink the block 
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		moo_oow_t rem = blk->size - size;
 | 
			
		||||
		if (rem >= MINBLKLEN) 
 | 
			
		||||
		{
 | 
			
		||||
			moo_xma_blk_t* tmp;
 | 
			
		||||
			moo_xma_blk_t* n = blk->b.next;
 | 
			
		||||
 | 
			
		||||
			/* the leftover is large enough to hold a block
 | 
			
		||||
			 * of minimum size. split the current block. 
 | 
			
		||||
			 * let 'tmp' point to the leftover. */
 | 
			
		||||
			tmp = (moo_xma_blk_t*)(((moo_uint8_t*)(blk + 1)) + size);
 | 
			
		||||
			tmp->avail = 1;
 | 
			
		||||
 | 
			
		||||
			if (n && n->avail)
 | 
			
		||||
			{
 | 
			
		||||
				/* merge with the next block */
 | 
			
		||||
				detach_from_freelist (xma, n);
 | 
			
		||||
 | 
			
		||||
				tmp->b.next = n->b.next;
 | 
			
		||||
				tmp->b.prev = blk;
 | 
			
		||||
				if (n->b.next) n->b.next->b.prev = tmp;
 | 
			
		||||
				blk->b.next = tmp;
 | 
			
		||||
				blk->size = size;
 | 
			
		||||
 | 
			
		||||
				tmp->size = rem - HDRSIZE + HDRSIZE + n->size;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
				xma->stat.alloc -= rem;
 | 
			
		||||
				/* rem - HDRSIZE(tmp) + HDRSIZE(n) */
 | 
			
		||||
				xma->stat.avail += rem;
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* link 'tmp' to the block list */
 | 
			
		||||
				tmp->b.next = n;
 | 
			
		||||
				tmp->b.prev = blk;
 | 
			
		||||
				if (n) n->b.prev = tmp;
 | 
			
		||||
				blk->b.next = tmp;
 | 
			
		||||
				blk->size = size;
 | 
			
		||||
 | 
			
		||||
				tmp->size = rem - HDRSIZE;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
				xma->stat.nfree++;
 | 
			
		||||
				xma->stat.alloc -= rem;
 | 
			
		||||
				xma->stat.avail += tmp->size;
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* add 'tmp' to the free list */
 | 
			
		||||
			attach_to_freelist (xma, tmp);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* moo_xma_calloc (moo_xma_t* xma, moo_oow_t size)
 | 
			
		||||
{
 | 
			
		||||
	void* ptr = moo_xma_alloc (xma, size);
 | 
			
		||||
	if (ptr) MOO_MEMSET (ptr, 0, size);
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* moo_xma_realloc (moo_xma_t* xma, void* b, moo_oow_t size)
 | 
			
		||||
{
 | 
			
		||||
	void* n;
 | 
			
		||||
 | 
			
		||||
	if (b == MOO_NULL) 
 | 
			
		||||
	{
 | 
			
		||||
		/* 'realloc' with NULL is the same as 'alloc' */
 | 
			
		||||
		n = moo_xma_alloc (xma, size);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* try reallocation by merging the adjacent continuous blocks */
 | 
			
		||||
		n = _realloc_merge (xma, b, size);
 | 
			
		||||
		if (n == MOO_NULL)
 | 
			
		||||
		{
 | 
			
		||||
			/* reallocation by merging failed. fall back to the slow
 | 
			
		||||
			 * allocation-copy-free scheme */
 | 
			
		||||
			n = moo_xma_alloc (xma, size);
 | 
			
		||||
			if (n)
 | 
			
		||||
			{
 | 
			
		||||
				MOO_MEMCPY (n, b, size);
 | 
			
		||||
				moo_xma_free (xma, b);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void moo_xma_free (moo_xma_t* xma, void* b)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_blk_t* blk = USR_TO_SYS(b);
 | 
			
		||||
 | 
			
		||||
	/*assert (blk->f.next == MOO_NULL);*/
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	/* update statistical variables */
 | 
			
		||||
	xma->stat.nused--;
 | 
			
		||||
	xma->stat.alloc -= blk->size;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if ((blk->b.prev && blk->b.prev->avail) &&
 | 
			
		||||
	    (blk->b.next && blk->b.next->avail))
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		 * Merge the block with surrounding blocks
 | 
			
		||||
		 *
 | 
			
		||||
		 *                    blk 
 | 
			
		||||
		 *           +-----+   |   +-----+     +------+
 | 
			
		||||
		 *           |     V   v   |     v     |      V
 | 
			
		||||
		 * +------------+------------+------------+------------+
 | 
			
		||||
		 * |     X      |            |     Y      |     Z      |
 | 
			
		||||
		 * +------------+------------+------------+------------+
 | 
			
		||||
		 *           ^     |     ^      |     ^      |
 | 
			
		||||
		 *           +-----+     +------+     +------+
 | 
			
		||||
		 *
 | 
			
		||||
		 *           
 | 
			
		||||
		 *      +-----------------------------------+
 | 
			
		||||
		 *      |                                   V
 | 
			
		||||
		 * +--------------------------------------+------------+
 | 
			
		||||
		 * |     X                                |     Z      |
 | 
			
		||||
		 * +--------------------------------------+------------+
 | 
			
		||||
		 *      ^                                   |
 | 
			
		||||
		 *      +-----------------------------------+
 | 
			
		||||
		 */
 | 
			
		||||
		moo_xma_blk_t* x = blk->b.prev;
 | 
			
		||||
		moo_xma_blk_t* y = blk->b.next;
 | 
			
		||||
		moo_xma_blk_t* z = y->b.next;
 | 
			
		||||
		moo_oow_t ns = HDRSIZE + blk->size + HDRSIZE;
 | 
			
		||||
		moo_oow_t bs = ns + y->size;
 | 
			
		||||
 | 
			
		||||
		detach_from_freelist (xma, x);
 | 
			
		||||
		detach_from_freelist (xma, y);
 | 
			
		||||
 | 
			
		||||
		x->size += bs;
 | 
			
		||||
		x->b.next = z;
 | 
			
		||||
		if (z) z->b.prev = x;
 | 
			
		||||
 | 
			
		||||
		attach_to_freelist (xma, x);
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
		xma->stat.nfree--;
 | 
			
		||||
		xma->stat.avail += ns;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	else if (blk->b.next && blk->b.next->avail)
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		 * Merge the block with the next block
 | 
			
		||||
		 *
 | 
			
		||||
		 *   blk
 | 
			
		||||
		 *    |      +-----+     +------+
 | 
			
		||||
		 *    v      |     v     |      V
 | 
			
		||||
		 * +------------+------------+------------+
 | 
			
		||||
		 * |            |     X      |     Y      |
 | 
			
		||||
		 * +------------+------------+------------+
 | 
			
		||||
		 *          ^      |     ^      |
 | 
			
		||||
		 *          +------+     +------+
 | 
			
		||||
		 *
 | 
			
		||||
		 *   blk
 | 
			
		||||
		 *    |      +------------------+
 | 
			
		||||
		 *    v      |                  V
 | 
			
		||||
		 * +-------------------------+------------+
 | 
			
		||||
		 * |                         |     Y      |
 | 
			
		||||
		 * +-------------------------+------------+
 | 
			
		||||
		 *          ^                   |
 | 
			
		||||
		 *          +-------------------+
 | 
			
		||||
		 */
 | 
			
		||||
		moo_xma_blk_t* x = blk->b.next;
 | 
			
		||||
		moo_xma_blk_t* y = x->b.next;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
		xma->stat.avail += blk->size + HDRSIZE;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		/* detach x from the free list */
 | 
			
		||||
		detach_from_freelist (xma, x);
 | 
			
		||||
 | 
			
		||||
		/* update the block availability */
 | 
			
		||||
		blk->avail = 1;
 | 
			
		||||
		/* update the block size. HDRSIZE for the header space in x */
 | 
			
		||||
		blk->size += HDRSIZE + x->size;
 | 
			
		||||
 | 
			
		||||
		/* update the backward link of Y */
 | 
			
		||||
		if (y) y->b.prev = blk;
 | 
			
		||||
		/* update the forward link of the block being freed */
 | 
			
		||||
		blk->b.next = y;
 | 
			
		||||
 | 
			
		||||
		/* attach blk to the free list */
 | 
			
		||||
		attach_to_freelist (xma, blk);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	else if (blk->b.prev && blk->b.prev->avail)
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		 * Merge the block with the previous block 
 | 
			
		||||
		 *
 | 
			
		||||
		 *                   blk
 | 
			
		||||
		 *          +-----+   |    +-----+  
 | 
			
		||||
		 *          |     V   v    |     v  
 | 
			
		||||
		 * +------------+------------+------------+
 | 
			
		||||
		 * |     X      |            |     Y      |
 | 
			
		||||
		 * +------------+------------+------------+
 | 
			
		||||
		 *         ^      |      ^      | 
 | 
			
		||||
		 *         +------+      +------+   
 | 
			
		||||
		 *
 | 
			
		||||
		 *               
 | 
			
		||||
		 *          +---------------------+  
 | 
			
		||||
		 *          |                     v  
 | 
			
		||||
		 * +-------------------------+------------+
 | 
			
		||||
		 * |     X                   |     Y      |
 | 
			
		||||
		 * +-------------------------+------------+
 | 
			
		||||
		 *         ^                    | 
 | 
			
		||||
		 *         +--------------------+   
 | 
			
		||||
		 *
 | 
			
		||||
		 */
 | 
			
		||||
		moo_xma_blk_t* x = blk->b.prev;
 | 
			
		||||
		moo_xma_blk_t* y = blk->b.next;
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
		xma->stat.avail += HDRSIZE + blk->size;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		detach_from_freelist (xma, x);
 | 
			
		||||
 | 
			
		||||
		x->size += HDRSIZE + blk->size;
 | 
			
		||||
		x->b.next = y;
 | 
			
		||||
		if (y) y->b.prev = x;
 | 
			
		||||
 | 
			
		||||
		attach_to_freelist (xma, x);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		blk->avail = 1;
 | 
			
		||||
		attach_to_freelist (xma, blk);
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
		xma->stat.nfree++;
 | 
			
		||||
		xma->stat.avail += blk->size;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void moo_xma_dump (moo_xma_t* xma, moo_xma_dumper_t dumper, void* ctx)
 | 
			
		||||
{
 | 
			
		||||
	moo_xma_blk_t* tmp;
 | 
			
		||||
	moo_oow_t fsum, asum; 
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	moo_oow_t isum;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	dumper (ctx, "<XMA DUMP>\n");
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	dumper (ctx, "== statistics ==\n");
 | 
			
		||||
	dumper (ctx, "total = %zu\n", xma->stat.total);
 | 
			
		||||
	dumper (ctx, "alloc = %zu\n", xma->stat.alloc);
 | 
			
		||||
	dumper (ctx, "avail = %zu\n", xma->stat.avail);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	dumper (ctx, "== blocks ==\n");
 | 
			
		||||
	dumper (ctx, " size               avail address\n");
 | 
			
		||||
	for (tmp = xma->head, fsum = 0, asum = 0; tmp; tmp = tmp->b.next)
 | 
			
		||||
	{
 | 
			
		||||
		dumper (ctx, " %-18zu %-5u %p\n", tmp->size, (unsigned int)tmp->avail, tmp);
 | 
			
		||||
		if (tmp->avail) fsum += tmp->size;
 | 
			
		||||
		else asum += tmp->size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	isum = (xma->stat.nfree + xma->stat.nused) * HDRSIZE;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	dumper (ctx, "---------------------------------------\n");
 | 
			
		||||
	dumper (ctx, "Allocated blocks: %18zu bytes\n", asum);
 | 
			
		||||
	dumper (ctx, "Available blocks: %18zu bytes\n", fsum);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	dumper (ctx, "Internal use    : %18zu bytes\n", isum);
 | 
			
		||||
	dumper (ctx, "Total           : %18zu bytes\n", (asum + fsum + isum));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(MOO_XMA_ENABLE_STAT)
 | 
			
		||||
	assert (asum == xma->stat.alloc);
 | 
			
		||||
	assert (fsum == xma->stat.avail);
 | 
			
		||||
	assert (isum == xma->stat.total - (xma->stat.alloc + xma->stat.avail));
 | 
			
		||||
	assert (asum + fsum + isum == xma->stat.total);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user