From a2bc284fce3cb98f39ace1140d3250c75fecef70 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Tue, 20 Sep 2011 14:29:01 +0200 Subject: [PATCH] use TLSF allocator. Add -m cmdline option --- Makefile | 2 +- src/Makefile | 10 +- src/lua.c | 233 ++++++++++-- src/lua.h | 4 +- src/tlsf.c | 1024 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tlsf.h | 39 ++ 6 files changed, 1264 insertions(+), 48 deletions(-) create mode 100644 src/tlsf.c create mode 100644 src/tlsf.h diff --git a/Makefile b/Makefile index 6e78f66..b616c29 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ RANLIB= ranlib PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris # What to install. -TO_BIN= lua luac +TO_BIN= lua-tlsf luac-tlsf TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 diff --git a/src/Makefile b/src/Makefile index e4a3cd6..712d41a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,14 +25,14 @@ PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ - lundump.o lvm.o lzio.o + lundump.o lvm.o lzio.o tlsf.o LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ lstrlib.o loadlib.o linit.o -LUA_T= lua +LUA_T= lua-tlsf LUA_O= lua.o -LUAC_T= luac +LUAC_T= luac-tlsf LUAC_O= luac.o print.o ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) @@ -166,7 +166,7 @@ ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h -lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h +lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h tlsf.h luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ lundump.h @@ -178,5 +178,5 @@ lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ lzio.h print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ ltm.h lzio.h lmem.h lopcodes.h lundump.h - +tlsf.o: tlsf.c tlsf.h # (end of Makefile) diff --git a/src/lua.c b/src/lua.c index 3a46609..1d46b5b 100644 --- a/src/lua.c +++ b/src/lua.c @@ -17,24 +17,133 @@ #include "lauxlib.h" #include "lualib.h" +#include "tlsf.h" +#define TLSF_POOL_MIN_SIZE 8*1024*1024 +#define TLSF_POOL_DEF_SIZE TLSF_POOL_MIN_SIZE +#define TLSF_DEBUG 1 +#define DEBUG_TLSF_ALLOC (1<<0) +#define DEBUG_TLSF_FREE (1<<1) +#define DEBUG_TLSF_TRACE (1<<20) + +#ifdef TLSF_DEBUG +static unsigned int tlsf_mask = 0; +# define _DBG(x, fmt, args...) do{ if (tlsf_mask & x) printf("%s: " fmt "\n", __FUNCTION__, ##args); } while(0); +#else +# define _DBG(x, fmt, args...) do { } while(0); +#endif + static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; +/* tlsf stuff */ +static char *pool; +static unsigned int pool_size; +#ifdef TLSF_DEBUG +static void tlsf_trace_hook(lua_State *L, lua_Debug *ar) +{ + lua_sethook(globalL, tlsf_trace_hook, 0, 0); + luaL_error(L, "memory allocation in tlsf trace mode"); +} -static void lstop (lua_State *L, lua_Debug *ar) { - (void)ar; /* unused arg. */ - lua_sethook(L, NULL, 0, 0); - luaL_error(L, "interrupted!"); +static int tlsf_trace(lua_State *L) +{ + int argc, enable, ret; + ret = 0; + argc = lua_gettop(L); + + if(argc == 0) { + lua_pushboolean(L, tlsf_mask & DEBUG_TLSF_TRACE); + ret = 1; + goto out; + } + + enable = lua_toboolean(L, 1); + + if(enable) { + tlsf_mask |= DEBUG_TLSF_TRACE; + } else { + lua_sethook(globalL, tlsf_trace_hook, 0, 1); + tlsf_mask &= ~DEBUG_TLSF_TRACE; + } + +out: + return ret; +} + +static int tlsf_warn(lua_State *L) +{ + int argc, enable, ret; + + ret = 0; + argc = lua_gettop(L); + + if( argc == 0) { + lua_pushboolean(L, tlsf_mask & (DEBUG_TLSF_ALLOC | DEBUG_TLSF_FREE)); + ret = 1; + goto out; + } + + enable = lua_toboolean(L, 1); + + if(enable) + tlsf_mask |= DEBUG_TLSF_ALLOC | DEBUG_TLSF_FREE; + else + tlsf_mask &= ~(DEBUG_TLSF_ALLOC | DEBUG_TLSF_FREE); +out: + return ret; +} + +static int tlsf_stats(lua_State *L) +{ + lua_pushinteger(L, get_used_size(pool)); + lua_pushinteger(L, get_max_size(pool)); + lua_pushinteger(L, pool_size); + return 3; } +static const struct luaL_Reg tlsf_f [] = { + {"stats", tlsf_stats }, + {"warn", tlsf_warn }, + {"trace", tlsf_trace }, + {NULL, NULL} +}; +#endif /* DEBUG */ + +static void *tlsf_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + (void)osize; + if (nsize == 0) { + _DBG(DEBUG_TLSF_FREE, "freeing 0x%lx, osize=%lu, nsize=%lu", (unsigned long) ptr, osize, nsize); + tlsf_free(ptr); + return NULL; + } + else { +#ifdef TLSF_DEBUG + if(DEBUG_TLSF_TRACE & tlsf_mask) { + lua_sethook(globalL, tlsf_trace_hook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT, 1); + } +#endif /* TLSF_DEBUG */ + + _DBG(DEBUG_TLSF_ALLOC, "allocating 0x%lx, osize=%lu, nsize=%lu", (unsigned long) ptr, osize, nsize); + return tlsf_realloc(ptr, nsize); + } +} + + +static void lstop (lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); + luaL_error(L, "interrupted!"); +} + static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ + terminate process (default action) */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } @@ -45,6 +154,7 @@ static void print_usage (void) { "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" " -l name require library " LUA_QL("name") "\n" + " -m mem pre-allocate " LUA_QL("mem") " bytes for real-time memory pool\n" " -i enter interactive mode after executing " LUA_QL("script") "\n" " -v show version information\n" " -- stop handling options\n" @@ -224,9 +334,9 @@ static void dotty (lua_State *L) { lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ @@ -242,14 +352,14 @@ static int handle_script (lua_State *L, char **argv, int n) { int narg = getargs(L, argv, n); /* collect arguments */ lua_setglobal(L, "arg"); fname = argv[n]; - if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); if (status == 0) status = docall(L, narg, 0); else - lua_pop(L, narg); + lua_pop(L, narg); return report(L, status); } @@ -257,33 +367,72 @@ static int handle_script (lua_State *L, char **argv, int n) { /* check that argument has no extra characters at the end */ #define notail(x) {if ((x)[2] != '\0') return -1;} +static int tlsf_handle_args (char **argv, int argc) +{ + int i; + long int size; + size=TLSF_POOL_DEF_SIZE; + + for(i=1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') /* not an option? */ + break; + if (argv[i][1] == 'm') { + if (argv[i][2] != '\0') { + size = strtol(&argv[i][2], NULL, 0); + goto alloc; + } else { + if (argv[i+1] == NULL) { + print_usage(); + return -1; + } else { + size = strtol(argv[i+1], NULL, 0); + goto alloc; + } + } + } + } + + alloc: + if(size < TLSF_POOL_MIN_SIZE) { + fprintf(stderr, "invalid amount of memory: 0x%lx\n", size); + return -1; + } + pool = malloc(size); + if(!pool) { + fprintf(stderr, "malloc failed to alloc 0x%lx bytes\n", size); + return -2; + } + pool_size = init_memory_pool(size, pool); + return 0; +} static int collectargs (char **argv, int *pi, int *pv, int *pe) { int i; for (i = 1; argv[i] != NULL; i++) { if (argv[i][0] != '-') /* not an option? */ - return i; + return i; switch (argv[i][1]) { /* option */ case '-': - notail(argv[i]); - return (argv[i+1] != NULL ? i+1 : 0); + notail(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); case '\0': - return i; + return i; case 'i': - notail(argv[i]); - *pi = 1; /* go through */ + notail(argv[i]); + *pi = 1; /* go through */ case 'v': - notail(argv[i]); - *pv = 1; - break; + notail(argv[i]); + *pv = 1; + break; + case 'm': /* tlsf memory size */ case 'e': - *pe = 1; /* go through */ + *pe = 1; /* go through */ case 'l': - if (argv[i][2] == '\0') { - i++; - if (argv[i] == NULL) return -1; - } - break; + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) return -1; + } + break; default: return -1; /* invalid option */ } } @@ -298,20 +447,20 @@ static int runargs (lua_State *L, char **argv, int n) { lua_assert(argv[i][0] == '-'); switch (argv[i][1]) { /* option */ case 'e': { - const char *chunk = argv[i] + 2; - if (*chunk == '\0') chunk = argv[++i]; - lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != 0) - return 1; - break; + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + lua_assert(chunk != NULL); + if (dostring(L, chunk, "=(command line)") != 0) + return 1; + break; } case 'l': { - const char *filename = argv[i] + 2; - if (*filename == '\0') filename = argv[++i]; - lua_assert(filename != NULL); - if (dolibrary(L, filename)) - return 1; /* stop if file fails */ - break; + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + lua_assert(filename != NULL); + if (dolibrary(L, filename)) + return 1; /* stop if file fails */ + break; } default: break; } @@ -346,6 +495,9 @@ static int pmain (lua_State *L) { if (argv[0] && argv[0][0]) progname = argv[0]; lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(L); /* open libraries */ +#ifdef TLSF_DEBUG + luaL_register(L, "tlsf", tlsf_f); +#endif lua_gc(L, LUA_GCRESTART, 0); s->status = handle_luainit(L); if (s->status != 0) return 0; @@ -373,11 +525,13 @@ static int pmain (lua_State *L) { return 0; } - int main (int argc, char **argv) { int status; struct Smain s; - lua_State *L = lua_open(); /* create state */ + status = tlsf_handle_args(argv, argc); + if(status) + return EXIT_FAILURE; + lua_State *L = lua_newstate(tlsf_alloc, 0); if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; @@ -389,4 +543,3 @@ int main (int argc, char **argv) { lua_close(L); return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } - diff --git a/src/lua.h b/src/lua.h index e4bdfd3..1646cff 100644 --- a/src/lua.h +++ b/src/lua.h @@ -16,8 +16,8 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.4" +#define LUA_VERSION "Lua 5.1 TLSF" +#define LUA_RELEASE "Lua 5.1.4 TLSF" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" diff --git a/src/tlsf.c b/src/tlsf.c new file mode 100644 index 0000000..eb4fdb3 --- /dev/null +++ b/src/tlsf.c @@ -0,0 +1,1024 @@ +/* + * Two Levels Segregate Fit memory allocator (TLSF) + * Version 2.4.6 + * + * Written by Miguel Masmano Tello + * + * Thanks to Ismael Ripoll for his suggestions and reviews + * + * Copyright (C) 2008, 2007, 2006, 2005, 2004 + * + * This code is released using a dual license strategy: GPL/LGPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of the GNU General Public License Version 2.0 + * Released under the terms of the GNU Lesser General Public License Version 2.1 + * + */ + +/* + * Code contributions: + * + * (Jul 28 2007) Herman ten Brugge : + * + * - Add 64 bit support. It now runs on x86_64 and solaris64. + * - I also tested this on vxworks/32and solaris/32 and i386/32 processors. + * - Remove assembly code. I could not measure any performance difference + * on my core2 processor. This also makes the code more portable. + * - Moved defines/typedefs from tlsf.h to tlsf.c + * - Changed MIN_BLOCK_SIZE to sizeof (free_ptr_t) and BHDR_OVERHEAD to + * (sizeof (bhdr_t) - MIN_BLOCK_SIZE). This does not change the fact + * that the minumum size is still sizeof + * (bhdr_t). + * - Changed all C++ comment style to C style. (// -> /.* ... *./) + * - Used ls_bit instead of ffs and ms_bit instead of fls. I did this to + * avoid confusion with the standard ffs function which returns + * different values. + * - Created set_bit/clear_bit fuctions because they are not present + * on x86_64. + * - Added locking support + extra file target.h to show how to use it. + * - Added get_used_size function (REMOVED in 2.4) + * - Added rtl_realloc and rtl_calloc function + * - Implemented realloc clever support. + * - Added some test code in the example directory. + * - Bug fixed (discovered by the rockbox project: www.rockbox.org). + * + * (Oct 23 2006) Adam Scislowicz: + * + * - Support for ARMv5 implemented + * + */ + +/*#define USE_SBRK (0) */ +/*#define USE_MMAP (0) */ + +#ifndef USE_PRINTF +#define USE_PRINTF (1) +#endif + +#include + +#ifndef TLSF_USE_LOCKS +#define TLSF_USE_LOCKS (0) +#endif + +#ifndef TLSF_STATISTIC +#define TLSF_STATISTIC (1) +#endif + +#ifndef USE_MMAP +#define USE_MMAP (0) +#endif + +#ifndef USE_SBRK +#define USE_SBRK (0) +#endif + +#ifndef CHECK_DOUBLE_FREE +#define CHECK_DOUBLE_FREE (0) +#endif + +#if TLSF_USE_LOCKS +#include "target.h" +#else +#define TLSF_CREATE_LOCK(_unused_) do{}while(0) +#define TLSF_DESTROY_LOCK(_unused_) do{}while(0) +#define TLSF_ACQUIRE_LOCK(_unused_) do{}while(0) +#define TLSF_RELEASE_LOCK(_unused_) do{}while(0) +#endif + +#if TLSF_STATISTIC +#define TLSF_ADD_SIZE(tlsf, b) do { \ + tlsf->used_size += (b->size & BLOCK_SIZE) + BHDR_OVERHEAD; \ + if (tlsf->used_size > tlsf->max_size) { \ + tlsf->max_size = tlsf->used_size; \ + } \ + } while(0) + +#define TLSF_REMOVE_SIZE(tlsf, b) do { \ + tlsf->used_size -= (b->size & BLOCK_SIZE) + BHDR_OVERHEAD; \ + } while(0) +#else +#define TLSF_ADD_SIZE(tlsf, b) do{}while(0) +#define TLSF_REMOVE_SIZE(tlsf, b) do{}while(0) +#endif + +#if USE_MMAP || USE_SBRK +#include +#endif + +#if USE_MMAP +#include +#endif + +#include "tlsf.h" + +#if !defined(__GNUC__) +#ifndef __inline__ +#define __inline__ +#endif +#endif + +/* The debug functions only can be used when _DEBUG_TLSF_ is set. */ +#ifndef _DEBUG_TLSF_ +#define _DEBUG_TLSF_ (0) +#endif + +/*************************************************************************/ +/* Definition of the structures used by TLSF */ + + +/* Some IMPORTANT TLSF parameters */ +/* Unlike the preview TLSF versions, now they are statics */ +#define BLOCK_ALIGN (sizeof(void *) * 2) + +#define MAX_FLI (30) +#define MAX_LOG2_SLI (5) +#define MAX_SLI (1 << MAX_LOG2_SLI) /* MAX_SLI = 2^MAX_LOG2_SLI */ + +#define FLI_OFFSET (6) /* tlsf structure just will manage blocks bigger */ +/* than 128 bytes */ +#define SMALL_BLOCK (128) +#define REAL_FLI (MAX_FLI - FLI_OFFSET) +#define MIN_BLOCK_SIZE (sizeof (free_ptr_t)) +#define BHDR_OVERHEAD (sizeof (bhdr_t) - MIN_BLOCK_SIZE) +#define TLSF_SIGNATURE (0x2A59FA59) + +#define PTR_MASK (sizeof(void *) - 1) +#define BLOCK_SIZE (0xFFFFFFFF - PTR_MASK) + +#define GET_NEXT_BLOCK(_addr, _r) ((bhdr_t *) ((char *) (_addr) + (_r))) +#define MEM_ALIGN ((BLOCK_ALIGN) - 1) +#define ROUNDUP_SIZE(_r) (((_r) + MEM_ALIGN) & ~MEM_ALIGN) +#define ROUNDDOWN_SIZE(_r) ((_r) & ~MEM_ALIGN) +#define ROUNDUP(_x, _v) ((((~(_x)) + 1) & ((_v)-1)) + (_x)) + +#define BLOCK_STATE (0x1) +#define PREV_STATE (0x2) + +/* bit 0 of the block size */ +#define FREE_BLOCK (0x1) +#define USED_BLOCK (0x0) + +/* bit 1 of the block size */ +#define PREV_FREE (0x2) +#define PREV_USED (0x0) + + +#define DEFAULT_AREA_SIZE (1024*10) + +#ifdef USE_MMAP +#define PAGE_SIZE (getpagesize()) +#endif + +#ifdef USE_PRINTF +#include +# define PRINT_MSG(fmt, args...) printf(fmt, ## args) +# define ERROR_MSG(fmt, args...) fprintf(stderr, fmt, ## args) +#else +# if !defined(PRINT_MSG) +# define PRINT_MSG(fmt, args...) +# endif +# if !defined(ERROR_MSG) +# define ERROR_MSG(fmt, args...) +# endif +#endif + +#ifndef ATTRIBUTE_UNUSED +#if defined(__GNUC__) +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#else +#define ATTRIBUTE_UNUSED +#endif +#endif + + +typedef unsigned int u32_t; /* NOTE: Make sure that this type is 4 bytes long on your computer */ +typedef unsigned char u8_t; /* NOTE: Make sure that this type is 1 byte on your computer */ + +typedef struct free_ptr_struct { + struct bhdr_struct *prev; + struct bhdr_struct *next; +} free_ptr_t; + +typedef struct bhdr_struct { + /* This pointer is just valid if the first bit of size is set */ + struct bhdr_struct *prev_hdr; + /* The size is stored in bytes */ + size_t size; /* bit 0 indicates whether the block is used and */ + /* bit 1 allows to know whether the previous block is free */ + union { + struct free_ptr_struct free_ptr; + u8_t buffer[1]; /*sizeof(struct free_ptr_struct)]; */ + } ptr; +} bhdr_t; + +/* This structure is embedded at the beginning of each area, giving us + * enough information to cope with a set of areas */ + +typedef struct area_info_struct { + bhdr_t *end; + struct area_info_struct *next; +} area_info_t; + +typedef struct TLSF_struct { + /* the TLSF's structure signature */ + u32_t tlsf_signature; + +#if TLSF_USE_LOCKS + TLSF_MLOCK_T lock; +#endif + +#if TLSF_STATISTIC + /* These can not be calculated outside tlsf because we + * do not know the sizes when freeing/reallocing memory. */ + size_t used_size; + size_t max_size; +#endif + + /* A linked list holding all the existing areas */ + area_info_t *area_head; + + /* the first-level bitmap */ + /* This array should have a size of REAL_FLI bits */ + u32_t fl_bitmap; + + /* the second-level bitmap */ + u32_t sl_bitmap[REAL_FLI]; + + bhdr_t *matrix[REAL_FLI][MAX_SLI]; +} tlsf_t; + + +/******************************************************************/ +/************** Helping functions **************************/ +/******************************************************************/ +static __inline__ void set_bit(int nr, u32_t * addr); +static __inline__ void clear_bit(int nr, u32_t * addr); +static __inline__ int ls_bit(int x); +static __inline__ int ms_bit(int x); +static __inline__ void MAPPING_SEARCH(size_t * _r, int *_fl, int *_sl); +static __inline__ void MAPPING_INSERT(size_t _r, int *_fl, int *_sl); +static __inline__ bhdr_t *FIND_SUITABLE_BLOCK(tlsf_t * _tlsf, int *_fl, int *_sl); +static __inline__ bhdr_t *process_area(void *area, size_t size); +#if USE_SBRK || USE_MMAP +static __inline__ void *get_new_area(size_t * size); +#endif + +static const int table[] = { + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, + 4, 4, + 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, + 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, + 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, + 7, 7, 7, 7, 7, 7, 7 +}; + +static __inline__ int ls_bit(int i) { + unsigned int a; + unsigned int x = i & -i; + + a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24); + return table[x >> a] + a; +} + +static __inline__ int ms_bit(int i) { + unsigned int a; + unsigned int x = (unsigned int) i; + + a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24); + return table[x >> a] + a; +} + +static __inline__ void set_bit(int nr, u32_t * addr) { + addr[nr >> 5] |= 1 << (nr & 0x1f); +} + +static __inline__ void clear_bit(int nr, u32_t * addr) { + addr[nr >> 5] &= ~(1 << (nr & 0x1f)); +} + +static __inline__ void MAPPING_SEARCH(size_t * _r, int *_fl, int *_sl) { + int _t; + + if (*_r < SMALL_BLOCK) { + *_fl = 0; + *_sl = *_r / (SMALL_BLOCK / MAX_SLI); + } else { + _t = (1 << (ms_bit(*_r) - MAX_LOG2_SLI)) - 1; + *_r = *_r + _t; + *_fl = ms_bit(*_r); + *_sl = (*_r >> (*_fl - MAX_LOG2_SLI)) - MAX_SLI; + *_fl -= FLI_OFFSET; + /*if ((*_fl -= FLI_OFFSET) < 0) // FL wil be always >0! + *_fl = *_sl = 0; + */ + *_r &= ~_t; + } +} + +static __inline__ void MAPPING_INSERT(size_t _r, int *_fl, int *_sl) { + if (_r < SMALL_BLOCK) { + *_fl = 0; + *_sl = _r / (SMALL_BLOCK / MAX_SLI); + } else { + *_fl = ms_bit(_r); + *_sl = (_r >> (*_fl - MAX_LOG2_SLI)) - MAX_SLI; + *_fl -= FLI_OFFSET; + } +} + + +static __inline__ bhdr_t *FIND_SUITABLE_BLOCK(tlsf_t * _tlsf, int *_fl, int *_sl) { + u32_t _tmp = _tlsf->sl_bitmap[*_fl] & (~0 << *_sl); + bhdr_t *_b = NULL; + + if (_tmp) { + *_sl = ls_bit(_tmp); + _b = _tlsf->matrix[*_fl][*_sl]; + } else { + *_fl = ls_bit(_tlsf->fl_bitmap & (~0 << (*_fl + 1))); + if (*_fl > 0) { /* likely */ + *_sl = ls_bit(_tlsf->sl_bitmap[*_fl]); + _b = _tlsf->matrix[*_fl][*_sl]; + } + } + return _b; +} + + +#define EXTRACT_BLOCK_HDR(_b, _tlsf, _fl, _sl) do { \ + _tlsf -> matrix [_fl] [_sl] = _b -> ptr.free_ptr.next; \ + if (_tlsf -> matrix[_fl][_sl]) \ + _tlsf -> matrix[_fl][_sl] -> ptr.free_ptr.prev = NULL; \ + else { \ + clear_bit (_sl, &_tlsf -> sl_bitmap [_fl]); \ + if (!_tlsf -> sl_bitmap [_fl]) \ + clear_bit (_fl, &_tlsf -> fl_bitmap); \ + } \ + _b -> ptr.free_ptr.prev = NULL; \ + _b -> ptr.free_ptr.next = NULL; \ + }while(0) + + +#define EXTRACT_BLOCK(_b, _tlsf, _fl, _sl) do { \ + if (_b -> ptr.free_ptr.next) \ + _b -> ptr.free_ptr.next -> ptr.free_ptr.prev = _b -> ptr.free_ptr.prev; \ + if (_b -> ptr.free_ptr.prev) \ + _b -> ptr.free_ptr.prev -> ptr.free_ptr.next = _b -> ptr.free_ptr.next; \ + if (_tlsf -> matrix [_fl][_sl] == _b) { \ + _tlsf -> matrix [_fl][_sl] = _b -> ptr.free_ptr.next; \ + if (!_tlsf -> matrix [_fl][_sl]) { \ + clear_bit (_sl, &_tlsf -> sl_bitmap[_fl]); \ + if (!_tlsf -> sl_bitmap [_fl]) \ + clear_bit (_fl, &_tlsf -> fl_bitmap); \ + } \ + } \ + _b -> ptr.free_ptr.prev = NULL; \ + _b -> ptr.free_ptr.next = NULL; \ + } while(0) + +#define INSERT_BLOCK(_b, _tlsf, _fl, _sl) do { \ + _b -> ptr.free_ptr.prev = NULL; \ + _b -> ptr.free_ptr.next = _tlsf -> matrix [_fl][_sl]; \ + if (_tlsf -> matrix [_fl][_sl]) \ + _tlsf -> matrix [_fl][_sl] -> ptr.free_ptr.prev = _b; \ + _tlsf -> matrix [_fl][_sl] = _b; \ + set_bit (_sl, &_tlsf -> sl_bitmap [_fl]); \ + set_bit (_fl, &_tlsf -> fl_bitmap); \ + } while(0) + +#if USE_SBRK || USE_MMAP +static __inline__ void *get_new_area(size_t * size) { + void *area; + +#if USE_SBRK + area = (void *) sbrk(0); + if (((void *) sbrk(*size)) != ((void *) -1)) + return area; +#endif + +#ifndef MAP_ANONYMOUS +/* https://dev.openwrt.org/ticket/322 */ +# define MAP_ANONYMOUS MAP_ANON +#endif + + +#if USE_MMAP + *size = ROUNDUP(*size, PAGE_SIZE); + if ((area = + mmap(0, *size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) + return area; +#endif + return ((void *) ~0); +} +#endif + +static __inline__ bhdr_t *process_area(void *area, size_t size) { + bhdr_t *b, *lb, *ib; + area_info_t *ai; + + ib = (bhdr_t *) area; + ib->size = + (sizeof(area_info_t) < + MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : ROUNDUP_SIZE(sizeof(area_info_t)) | USED_BLOCK | + PREV_USED; + b = (bhdr_t *) GET_NEXT_BLOCK(ib->ptr.buffer, ib->size & BLOCK_SIZE); + b->size = + ROUNDDOWN_SIZE(size - 3 * BHDR_OVERHEAD - (ib->size & BLOCK_SIZE)) | USED_BLOCK | PREV_USED; + b->ptr.free_ptr.prev = b->ptr.free_ptr.next = 0; + lb = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE); + lb->prev_hdr = b; + lb->size = 0 | USED_BLOCK | PREV_FREE; + ai = (area_info_t *) ib->ptr.buffer; + ai->next = 0; + ai->end = lb; + return ib; +} + +/******************************************************************/ +/******************** Begin of the allocator code *****************/ +/******************************************************************/ + +static char *mp = NULL; /* Default memory pool. */ + +/******************************************************************/ +size_t init_memory_pool(size_t mem_pool_size, void *mem_pool) { +/******************************************************************/ + tlsf_t *tlsf; + bhdr_t *b, *ib; + + if (!mem_pool || !mem_pool_size || mem_pool_size < sizeof(tlsf_t) + BHDR_OVERHEAD * 8) { + ERROR_MSG("init_memory_pool (): memory_pool invalid\n"); + return (size_t) - 1; + } + + if (((unsigned long) mem_pool & PTR_MASK)) { + ERROR_MSG("init_memory_pool (): mem_pool must be aligned to a word\n"); + return (size_t) - 1; + } + tlsf = (tlsf_t *) mem_pool; + /* Check if already initialised */ + if (tlsf->tlsf_signature == TLSF_SIGNATURE) { + mp = (char *) mem_pool; + b = GET_NEXT_BLOCK(mp, ROUNDUP_SIZE(sizeof(tlsf_t))); + return b->size & BLOCK_SIZE; + } + + mp = (char *) mem_pool; + + /* Zeroing the memory pool */ + memset(mem_pool, 0, sizeof(tlsf_t)); + + tlsf->tlsf_signature = TLSF_SIGNATURE; + + TLSF_CREATE_LOCK(&tlsf->lock); + + ib = process_area(GET_NEXT_BLOCK + (mem_pool, ROUNDUP_SIZE(sizeof(tlsf_t))), + ROUNDDOWN_SIZE(mem_pool_size - sizeof(tlsf_t))); + b = GET_NEXT_BLOCK(ib->ptr.buffer, ib->size & BLOCK_SIZE); + free_ex(b->ptr.buffer, tlsf); + tlsf->area_head = (area_info_t *) ib->ptr.buffer; + +#if TLSF_STATISTIC + tlsf->used_size = mem_pool_size - (b->size & BLOCK_SIZE); + tlsf->max_size = tlsf->used_size; +#endif + + return (b->size & BLOCK_SIZE); +} + +/******************************************************************/ +size_t add_new_area(void *area, size_t area_size, void *mem_pool) { +/******************************************************************/ + tlsf_t *tlsf = (tlsf_t *) mem_pool; + area_info_t *ptr, *ptr_prev, *ai; + bhdr_t *ib0, *b0, *lb0, *ib1, *b1, *lb1, *next_b; + + memset(area, 0, area_size); + ptr = tlsf->area_head; + ptr_prev = 0; + + ib0 = process_area(area, area_size); + b0 = GET_NEXT_BLOCK(ib0->ptr.buffer, ib0->size & BLOCK_SIZE); + lb0 = GET_NEXT_BLOCK(b0->ptr.buffer, b0->size & BLOCK_SIZE); + + /* Before inserting the new area, we have to merge this area with the + already existing ones */ + + while (ptr) { + ib1 = (bhdr_t *) ((char *) ptr - BHDR_OVERHEAD); + b1 = GET_NEXT_BLOCK(ib1->ptr.buffer, ib1->size & BLOCK_SIZE); + lb1 = ptr->end; + + /* Merging the new area with the next physically contigous one */ + if ((unsigned long) ib1 == (unsigned long) lb0 + BHDR_OVERHEAD) { + if (tlsf->area_head == ptr) { + tlsf->area_head = ptr->next; + ptr = ptr->next; + } else { + ptr_prev->next = ptr->next; + ptr = ptr->next; + } + + b0->size = + ROUNDDOWN_SIZE((b0->size & BLOCK_SIZE) + + (ib1->size & BLOCK_SIZE) + + 2 * BHDR_OVERHEAD) | USED_BLOCK | PREV_USED; + + b1->prev_hdr = b0; + lb0 = lb1; + + continue; + } + + /* Merging the new area with the previous physically contigous + one */ + if ((unsigned long) lb1->ptr.buffer == (unsigned long) ib0) { + if (tlsf->area_head == ptr) { + tlsf->area_head = ptr->next; + ptr = ptr->next; + } else { + ptr_prev->next = ptr->next; + ptr = ptr->next; + } + + lb1->size = + ROUNDDOWN_SIZE((b0->size & BLOCK_SIZE) + + (ib0->size & BLOCK_SIZE) + + 2 * BHDR_OVERHEAD) | USED_BLOCK | (lb1->size & PREV_STATE); + next_b = GET_NEXT_BLOCK(lb1->ptr.buffer, lb1->size & BLOCK_SIZE); + next_b->prev_hdr = lb1; + b0 = lb1; + ib0 = ib1; + + continue; + } + ptr_prev = ptr; + ptr = ptr->next; + } + + /* Inserting the area in the list of linked areas */ + ai = (area_info_t *) ib0->ptr.buffer; + ai->next = tlsf->area_head; + ai->end = lb0; + tlsf->area_head = ai; + free_ex(b0->ptr.buffer, mem_pool); + return (b0->size & BLOCK_SIZE); +} + + +/******************************************************************/ +size_t get_used_size(void *mem_pool ATTRIBUTE_UNUSED) { +/******************************************************************/ +#if TLSF_STATISTIC + return ((tlsf_t *) mem_pool)->used_size; +#else + return 0; +#endif +} + +/******************************************************************/ +size_t get_max_size(void *mem_pool ATTRIBUTE_UNUSED) { +/******************************************************************/ +#if TLSF_STATISTIC + return ((tlsf_t *) mem_pool)->max_size; +#else + return 0; +#endif +} + +/******************************************************************/ +void destroy_memory_pool(void *mem_pool) { +/******************************************************************/ + tlsf_t *tlsf = (tlsf_t *) mem_pool; + + tlsf->tlsf_signature = 0; + + TLSF_DESTROY_LOCK(&tlsf->lock); + +} + + +/******************************************************************/ +void *tlsf_malloc(size_t size) { +/******************************************************************/ + void *ret; + +#if USE_MMAP || USE_SBRK + if (!mp) { + size_t area_size; + void *area; + + area_size = sizeof(tlsf_t) + BHDR_OVERHEAD * 8; /* Just a safety constant */ + area_size = (area_size > DEFAULT_AREA_SIZE) ? area_size : DEFAULT_AREA_SIZE; + area = get_new_area(&area_size); + if (area == ((void *) ~0)) + return NULL; /* Not enough system memory */ + init_memory_pool(area_size, area); + } +#endif + + TLSF_ACQUIRE_LOCK(&((tlsf_t *) mp)->lock); + + ret = malloc_ex(size, mp); + + TLSF_RELEASE_LOCK(&((tlsf_t *) mp)->lock); + + return ret; +} + +/******************************************************************/ +void tlsf_free(void *ptr) { +/******************************************************************/ + + TLSF_ACQUIRE_LOCK(&((tlsf_t *) mp)->lock); + + free_ex(ptr, mp); + + TLSF_RELEASE_LOCK(&((tlsf_t *) mp)->lock); + +} + +/******************************************************************/ +void *tlsf_realloc(void *ptr, size_t size) { +/******************************************************************/ + void *ret; + +#if USE_MMAP || USE_SBRK + if (!mp) { + return tlsf_malloc(size); + } +#endif + + TLSF_ACQUIRE_LOCK(&((tlsf_t *) mp)->lock); + + ret = realloc_ex(ptr, size, mp); + + TLSF_RELEASE_LOCK(&((tlsf_t *) mp)->lock); + + return ret; +} + +/******************************************************************/ +void *tlsf_calloc(size_t nelem, size_t elem_size) { +/******************************************************************/ + void *ret; + + TLSF_ACQUIRE_LOCK(&((tlsf_t *) mp)->lock); + + ret = calloc_ex(nelem, elem_size, mp); + + TLSF_RELEASE_LOCK(&((tlsf_t *) mp)->lock); + + return ret; +} + +/******************************************************************/ +void *malloc_ex(size_t size, void *mem_pool) { +/******************************************************************/ + tlsf_t *tlsf = (tlsf_t *) mem_pool; + bhdr_t *b, *b2, *next_b; + int fl, sl; + size_t tmp_size; + + size = (size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : ROUNDUP_SIZE(size); + + /* Rounding up the requested size and calculating fl and sl */ + MAPPING_SEARCH(&size, &fl, &sl); + + /* Searching a free block, recall that this function changes the values of fl and sl, + so they are not longer valid when the function fails */ + b = FIND_SUITABLE_BLOCK(tlsf, &fl, &sl); +#if USE_MMAP || USE_SBRK + if (!b) { + size_t area_size; + void *area; + /* Growing the pool size when needed */ + area_size = size + BHDR_OVERHEAD * 8; /* size plus enough room for the requered headers. */ + area_size = (area_size > DEFAULT_AREA_SIZE) ? area_size : DEFAULT_AREA_SIZE; + area = get_new_area(&area_size); /* Call sbrk or mmap */ + if (area == ((void *) ~0)) + return NULL; /* Not enough system memory */ + add_new_area(area, area_size, mem_pool); + /* Rounding up the requested size and calculating fl and sl */ + MAPPING_SEARCH(&size, &fl, &sl); + /* Searching a free block */ + b = FIND_SUITABLE_BLOCK(tlsf, &fl, &sl); + } +#endif + if (!b) + return NULL; /* Not found */ + + EXTRACT_BLOCK_HDR(b, tlsf, fl, sl); + + /*-- found: */ + next_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE); + /* Should the block be split? */ + tmp_size = (b->size & BLOCK_SIZE) - size; + if (tmp_size >= sizeof(bhdr_t)) { + tmp_size -= BHDR_OVERHEAD; + b2 = GET_NEXT_BLOCK(b->ptr.buffer, size); + b2->size = tmp_size | FREE_BLOCK | PREV_USED; + next_b->prev_hdr = b2; + MAPPING_INSERT(tmp_size, &fl, &sl); + INSERT_BLOCK(b2, tlsf, fl, sl); + + b->size = size | (b->size & PREV_STATE); + } else { + next_b->size &= (~PREV_FREE); + b->size &= (~FREE_BLOCK); /* Now it's used */ + } + + TLSF_ADD_SIZE(tlsf, b); + + return (void *) b->ptr.buffer; +} + +/******************************************************************/ +void free_ex(void *ptr, void *mem_pool) { +/******************************************************************/ + tlsf_t *tlsf = (tlsf_t *) mem_pool; + bhdr_t *b, *tmp_b; + int fl = 0, sl = 0; + + if (!ptr) { + return; + } + b = (bhdr_t *) ((char *) ptr - BHDR_OVERHEAD); + +#ifdef CHECK_DOUBLE_FREE + if (b->size & FREE_BLOCK) { + ERROR_MSG("free_ex(): double free %p\n", ptr); + return; + } +#endif + + b->size |= FREE_BLOCK; + + TLSF_REMOVE_SIZE(tlsf, b); + + b->ptr.free_ptr.prev = NULL; + b->ptr.free_ptr.next = NULL; + tmp_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE); + if (tmp_b->size & FREE_BLOCK) { + MAPPING_INSERT(tmp_b->size & BLOCK_SIZE, &fl, &sl); + EXTRACT_BLOCK(tmp_b, tlsf, fl, sl); + b->size += (tmp_b->size & BLOCK_SIZE) + BHDR_OVERHEAD; + } + if (b->size & PREV_FREE) { + tmp_b = b->prev_hdr; + MAPPING_INSERT(tmp_b->size & BLOCK_SIZE, &fl, &sl); + EXTRACT_BLOCK(tmp_b, tlsf, fl, sl); + tmp_b->size += (b->size & BLOCK_SIZE) + BHDR_OVERHEAD; + b = tmp_b; + } + MAPPING_INSERT(b->size & BLOCK_SIZE, &fl, &sl); + INSERT_BLOCK(b, tlsf, fl, sl); + + tmp_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE); + tmp_b->size |= PREV_FREE; + tmp_b->prev_hdr = b; +} + +/******************************************************************/ +void *realloc_ex(void *ptr, size_t new_size, void *mem_pool) { +/******************************************************************/ + tlsf_t *tlsf = (tlsf_t *) mem_pool; + void *ptr_aux; + unsigned int cpsize; + bhdr_t *b, *tmp_b, *next_b; + int fl, sl; + size_t tmp_size; + + if (!ptr) { + if (new_size) + return (void *) malloc_ex(new_size, mem_pool); + if (!new_size) + return NULL; + } else if (!new_size) { + free_ex(ptr, mem_pool); + return NULL; + } + + b = (bhdr_t *) ((char *) ptr - BHDR_OVERHEAD); + +#ifdef CHECK_DOUBLE_FREE + if (b->size & FREE_BLOCK) { + ERROR_MSG("realloc_ex(): invalid pointer %p\n", ptr); + return (void *) malloc_ex(new_size, mem_pool); + } +#endif + + next_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE); + new_size = (new_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : ROUNDUP_SIZE(new_size); + tmp_size = (b->size & BLOCK_SIZE); + if (new_size <= tmp_size) { + TLSF_REMOVE_SIZE(tlsf, b); + if (next_b->size & FREE_BLOCK) { + MAPPING_INSERT(next_b->size & BLOCK_SIZE, &fl, &sl); + EXTRACT_BLOCK(next_b, tlsf, fl, sl); + tmp_size += (next_b->size & BLOCK_SIZE) + BHDR_OVERHEAD; + next_b = GET_NEXT_BLOCK(next_b->ptr.buffer, next_b->size & BLOCK_SIZE); + /* We allways reenter this free block because tmp_size will + be greater then sizeof (bhdr_t) */ + } + tmp_size -= new_size; + if (tmp_size >= sizeof(bhdr_t)) { + tmp_size -= BHDR_OVERHEAD; + tmp_b = GET_NEXT_BLOCK(b->ptr.buffer, new_size); + tmp_b->size = tmp_size | FREE_BLOCK | PREV_USED; + next_b->prev_hdr = tmp_b; + next_b->size |= PREV_FREE; + MAPPING_INSERT(tmp_size, &fl, &sl); + INSERT_BLOCK(tmp_b, tlsf, fl, sl); + b->size = new_size | (b->size & PREV_STATE); + } + TLSF_ADD_SIZE(tlsf, b); + return (void *) b->ptr.buffer; + } + if ((next_b->size & FREE_BLOCK)) { + if (new_size <= (tmp_size + (next_b->size & BLOCK_SIZE))) { + TLSF_REMOVE_SIZE(tlsf, b); + MAPPING_INSERT(next_b->size & BLOCK_SIZE, &fl, &sl); + EXTRACT_BLOCK(next_b, tlsf, fl, sl); + b->size += (next_b->size & BLOCK_SIZE) + BHDR_OVERHEAD; + next_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE); + next_b->prev_hdr = b; + next_b->size &= ~PREV_FREE; + tmp_size = (b->size & BLOCK_SIZE) - new_size; + if (tmp_size >= sizeof(bhdr_t)) { + tmp_size -= BHDR_OVERHEAD; + tmp_b = GET_NEXT_BLOCK(b->ptr.buffer, new_size); + tmp_b->size = tmp_size | FREE_BLOCK | PREV_USED; + next_b->prev_hdr = tmp_b; + next_b->size |= PREV_FREE; + MAPPING_INSERT(tmp_size, &fl, &sl); + INSERT_BLOCK(tmp_b, tlsf, fl, sl); + b->size = new_size | (b->size & PREV_STATE); + } + TLSF_ADD_SIZE(tlsf, b); + return (void *) b->ptr.buffer; + } + } + + if (!(ptr_aux = malloc_ex(new_size, mem_pool))) { + return NULL; + } + + cpsize = ((b->size & BLOCK_SIZE) > new_size) ? new_size : (b->size & BLOCK_SIZE); + + memcpy(ptr_aux, ptr, cpsize); + + free_ex(ptr, mem_pool); + return ptr_aux; +} + + +/******************************************************************/ +void *calloc_ex(size_t nelem, size_t elem_size, void *mem_pool) { +/******************************************************************/ + void *ptr; + + if (nelem <= 0 || elem_size <= 0) + return NULL; + + if (!(ptr = malloc_ex(nelem * elem_size, mem_pool))) + return NULL; + memset(ptr, 0, nelem * elem_size); + + return ptr; +} + + + +#if _DEBUG_TLSF_ + +/*************** DEBUG FUNCTIONS **************/ + +/* The following functions have been designed to ease the debugging of */ +/* the TLSF structure. For non-developing purposes, it may be they */ +/* haven't too much worth. To enable them, _DEBUG_TLSF_ must be set. */ + +extern void dump_memory_region(unsigned char *mem_ptr, unsigned int size); +extern void print_block(bhdr_t * b); +extern void print_tlsf(tlsf_t * tlsf); +void print_all_blocks(tlsf_t * tlsf); + +void dump_memory_region(unsigned char *mem_ptr, unsigned int size) { + + unsigned long begin = (unsigned long) mem_ptr; + unsigned long end = (unsigned long) mem_ptr + size; + int column = 0; + + begin >>= 2; + begin <<= 2; + + end >>= 2; + end++; + end <<= 2; + + PRINT_MSG("\nMemory region dumped: 0x%lx - 0x%lx\n\n", begin, end); + + column = 0; + PRINT_MSG("0x%lx ", begin); + + while (begin < end) { + if (((unsigned char *) begin)[0] == 0) + PRINT_MSG("00"); + else + PRINT_MSG("%02x", ((unsigned char *) begin)[0]); + if (((unsigned char *) begin)[1] == 0) + PRINT_MSG("00 "); + else + PRINT_MSG("%02x ", ((unsigned char *) begin)[1]); + begin += 2; + column++; + if (column == 8) { + PRINT_MSG("\n0x%lx ", begin); + column = 0; + } + + } + PRINT_MSG("\n\n"); +} + +void print_block(bhdr_t * b) { + if (!b) + return; + PRINT_MSG(">> [%p] (", b); + if ((b->size & BLOCK_SIZE)) + PRINT_MSG("%lu bytes, ", (unsigned long) (b->size & BLOCK_SIZE)); + else + PRINT_MSG("sentinel, "); + if ((b->size & BLOCK_STATE) == FREE_BLOCK) + PRINT_MSG("free [%p, %p], ", b->ptr.free_ptr.prev, b->ptr.free_ptr.next); + else + PRINT_MSG("used, "); + if ((b->size & PREV_STATE) == PREV_FREE) + PRINT_MSG("prev. free [%p])\n", b->prev_hdr); + else + PRINT_MSG("prev used)\n"); +} + +void print_tlsf(tlsf_t * tlsf) { + bhdr_t *next; + int i, j; + + PRINT_MSG("\nTLSF at %p\n", tlsf); + + PRINT_MSG("FL bitmap: 0x%x\n\n", (unsigned) tlsf->fl_bitmap); + + for (i = 0; i < REAL_FLI; i++) { + if (tlsf->sl_bitmap[i]) + PRINT_MSG("SL bitmap 0x%x\n", (unsigned) tlsf->sl_bitmap[i]); + for (j = 0; j < MAX_SLI; j++) { + next = tlsf->matrix[i][j]; + if (next) + PRINT_MSG("-> [%d][%d]\n", i, j); + while (next) { + print_block(next); + next = next->ptr.free_ptr.next; + } + } + } +} + +void print_all_blocks(tlsf_t * tlsf) { + area_info_t *ai; + bhdr_t *next; + PRINT_MSG("\nTLSF at %p\nALL BLOCKS\n\n", tlsf); + ai = tlsf->area_head; + while (ai) { + next = (bhdr_t *) ((char *) ai - BHDR_OVERHEAD); + while (next) { + print_block(next); + if ((next->size & BLOCK_SIZE)) + next = GET_NEXT_BLOCK(next->ptr.buffer, next->size & BLOCK_SIZE); + else + next = NULL; + } + ai = ai->next; + } +} + +#endif diff --git a/src/tlsf.h b/src/tlsf.h new file mode 100644 index 0000000..29ffb7f --- /dev/null +++ b/src/tlsf.h @@ -0,0 +1,39 @@ +/* + * Two Levels Segregate Fit memory allocator (TLSF) + * Version 2.4.6 + * + * Written by Miguel Masmano Tello + * + * Thanks to Ismael Ripoll for his suggestions and reviews + * + * Copyright (C) 2008, 2007, 2006, 2005, 2004 + * + * This code is released using a dual license strategy: GPL/LGPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of the GNU General Public License Version 2.0 + * Released under the terms of the GNU Lesser General Public License Version 2.1 + * + */ + +#ifndef _TLSF_H_ +#define _TLSF_H_ + +#include + +extern size_t init_memory_pool(size_t, void *); +extern size_t get_used_size(void *); +extern size_t get_max_size(void *); +extern void destroy_memory_pool(void *); +extern size_t add_new_area(void *, size_t, void *); +extern void *malloc_ex(size_t, void *); +extern void free_ex(void *, void *); +extern void *realloc_ex(void *, size_t, void *); +extern void *calloc_ex(size_t, size_t, void *); + +extern void *tlsf_malloc(size_t size); +extern void tlsf_free(void *ptr); +extern void *tlsf_realloc(void *ptr, size_t size); +extern void *tlsf_calloc(size_t nelem, size_t elem_size); + +#endif