diff options
| author | Daniel Stenberg <daniel@haxx.se> | 2004-01-08 15:42:18 +0000 |
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2004-01-08 15:42:18 +0000 |
| commit | 21fba08fc3a66c7f395b2a95b3e6dd3dfd9c8002 (patch) | |
| tree | c09efc5f6b49743bf2aa5d1ce6076982057b4eb5 /firmware/malloc/dmalloc.c | |
| parent | e428647018d98a0e9678120ceb4b8b0d538a0099 (diff) | |
| download | rockbox-21fba08fc3a66c7f395b2a95b3e6dd3dfd9c8002.zip rockbox-21fba08fc3a66c7f395b2a95b3e6dd3dfd9c8002.tar.gz rockbox-21fba08fc3a66c7f395b2a95b3e6dd3dfd9c8002.tar.bz2 rockbox-21fba08fc3a66c7f395b2a95b3e6dd3dfd9c8002.tar.xz | |
not used
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4209 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/malloc/dmalloc.c')
| -rw-r--r-- | firmware/malloc/dmalloc.c | 634 |
1 files changed, 0 insertions, 634 deletions
diff --git a/firmware/malloc/dmalloc.c b/firmware/malloc/dmalloc.c deleted file mode 100644 index 7f1690b..0000000 --- a/firmware/malloc/dmalloc.c +++ /dev/null @@ -1,634 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Daniel Stenberg - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -/***************************************************************************** - * - * Dynamic small-blocks Memory Allocation - * - * Author: Daniel Stenberg <daniel@haxx.se> - * - * Read THOUGHTS for theories and details on the implementation. - * - *****************************************************************************/ - -#include <stdio.h> -#include <string.h> /* memcpy */ - -#ifdef DEBUG_MALLOC -#include <stdarg.h> -#endif - -#ifdef PSOS -#include <psos.h> -#define SEMAPHORE /* the PSOS routines use semaphore protection */ -#else - -#endif - -#define BMALLOC /* we use our own big-malloc system */ - -#ifdef BMALLOC -#include "bmalloc.h" -#endif - -/* Each TOP takes care of a chain of BLOCKS */ -struct MemTop { - struct MemBlock *chain; /* pointer to the BLOCK chain */ - long nfree; /* total number of free FRAGMENTS in the chain */ - short nmax; /* total number of FRAGMENTS in this kind of BLOCK */ - size_t fragsize; /* the size of each FRAGMENT */ - -#ifdef SEMAPHORE /* if we're protecting the list with SEMAPHORES */ - long semaphore_id; /* semaphore used to lock this particular list */ -#endif - -}; - -/* Each BLOCK takes care of an amount of FRAGMENTS */ -struct MemBlock { - struct MemTop *top; /* our TOP struct */ - struct MemBlock *next; /* next BLOCK */ - struct MemBlock *prev; /* prev BLOCK */ - - struct MemFrag *first; /* the first free FRAGMENT in this block */ - - short nfree; /* number of free FRAGMENTS in this BLOCK */ -}; - -/* This is the data kept in all _free_ FRAGMENTS */ -struct MemFrag { - struct MemFrag *next; /* next free FRAGMENT */ - struct MemFrag *prev; /* prev free FRAGMENT */ -}; - -/* This is the data kept in all _allocated_ FRAGMENTS and BLOCKS. We add this - to the allocation size first thing in the ALLOC function to make room for - this smoothly. */ - -struct MemInfo { - void *block; - /* which BLOCK is our father, if BLOCK_BIT is set it means this is a - stand-alone, large allocation and then the rest of the bits should be - treated as the size of the block */ -#define BLOCK_BIT 1 -}; - -/* ---------------------------------------------------------------------- */ -/* Defines */ -/* ---------------------------------------------------------------------- */ - -#ifdef DEBUG_VERBOSE -#define MEMINCR(addr,x) memchange(addr, x) -#define MEMDECR(addr,x) memchange(addr,-(x)) -#else -#define MEMINCR(a,x) -#define MEMDECR(a,x) -#endif - -/* The low level functions used to get memory from the OS and to return memory - to the OS, we may also define a stub that does the actual allocation and - free, these are the defined function names used in the dmalloc system - anyway: */ -#ifdef PSOS - -#ifdef DEBUG_MALLOC -#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size) -#define DMEM_OSFREEMEM(x) dbgfree(x) -#else -#define DMEM_OSALLOCMEM(size,pointer,type) rn_getseg(0,size,RN_NOWAIT,0,(void **)&pointer) -/* Similar, but this returns the memory */ -#define DMEM_OSFREEMEM(x) rn_retseg(0, x) -#endif - -/* Argument: <id> */ -#define SEMAPHOREOBTAIN(x) sm_p(x, SM_WAIT, 0) -/* Argument: <id> */ -#define SEMAPHORERETURN(x) sm_v(x) -/* Argument: <name> <id-variable name> */ -#define SEMAPHORECREATE(x,y) sm_create(x, 1, SM_FIFO, (ULONG *)&(y)) - -#else -#ifdef BMALLOC /* use our own big-memory-allocation system */ -#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)bmalloc(size) -#define DMEM_OSFREEMEM(x) bfree(x) -#elif DEBUG_MALLOC -#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size) -#define DMEM_OSFREEMEM(x) dbgfree(x) -#else -#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)malloc(size) -#define DMEM_OSFREEMEM(x) free(x) -#endif -#endif - - -/* the largest memory allocation that is made a FRAGMENT: (grab the highest - number from the list below) */ -#define DMEM_LARGESTSIZE 2032 - -/* The total size of a BLOCK used for FRAGMENTS - In order to make this use only *1* even alignment from the big-block- - allocation-system (possible the bmalloc() system also written by me) - we need to subtract the [maximum] struct sizes that could get added all - the way through to the grab from the memory. */ -#define DMEM_BLOCKSIZE 4064 /* (4096 - sizeof(struct MemBlock) - 12) */ - -/* Since the blocksize isn't an even 2^X story anymore, we make a table with - the FRAGMENT sizes and amounts that fills up a BLOCK nicely */ - -/* a little 'bc' script that helps us maximize the usage: - - for 32-bit aligned addresses (SPARC crashes otherwise): - for(i=20; i<2040; i+=4) { a=4064/i; if(a*i >= 4060) { {i;} } } - - I try to approximate a double of each size, starting with ~20. We don't do - ODD sizes since several CPU flavours dump core when accessing such - addresses. We try to do 32-bit aligned to make ALL kinds of CPUs to remain - happy with us. - */ - -static const unsigned short qinfo[]= { - 20, 28, 52, 116, 312, 580, 1016, 2032 -}; - -#define MIN(x,y) ((x)<(y)?(x):(y)) - -/* ---------------------------------------------------------------------- */ -/* Globals */ -/* ---------------------------------------------------------------------- */ - -/* keeper of the chain of BLOCKS */ -static struct MemTop top[ sizeof(qinfo)/sizeof(qinfo[0]) ]; - -/* ---------------------------------------------------------------------- */ -/* Start of the real code */ -/* ---------------------------------------------------------------------- */ - -#ifdef DEBUG_MALLOC -/************ - * A few functions that are verbose and tells us about the current status - * of the dmalloc system - ***********/ - -void dmalloc_status(void) -{ - unsigned int i; - int used; - int num; - int totalfree=0; - struct MemBlock *block; - for(i=0; i<sizeof(qinfo)/sizeof(qinfo[0]);i++) { - block = top[i].chain; - used = 0; - num = 0; - while(block) { - used += top[i].nmax-block->nfree; - num++; - block = block->next; - } - printf("Q %d (FRAG %4d), USED %4d FREE %4ld (SIZE %4ld) BLOCKS %d\n", - i, top[i].fragsize, used, top[i].nfree, - top[i].nfree*top[i].fragsize, num); - totalfree += top[i].nfree*top[i].fragsize; - } - printf("Total unused memory stolen by dmalloc: %d\n", totalfree); -} -#endif - -#ifdef DEBUG_VERBOSE -static void dmalloc_failed(size_t size) -{ - printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size); - dmalloc_status(); -} -#else -#define dmalloc_failed(x) -#endif - -#ifdef DEBUG_VERBOSE - -#define DBG(x) syslog x - -void syslog(char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); -} - -void memchange(void *a, int x) -{ - static int memory=0; - static int count=0; - static int max=0; - if(memory > max) - max = memory; - memory += x; - DBG(("%d. PTR %p / %d TOTAL %d MAX %d\n", ++count, a, x, memory, max)); -} -#else -#define DBG(x) -#endif - -/**************************************************************************** - * - * FragBlock() - * - * This function makes FRAGMENTS of the BLOCK sent as argument. - * - ***************************************************************************/ - -static void FragBlock(char *memp, int size) -{ - struct MemFrag *frag=(struct MemFrag *)memp; - struct MemFrag *prev=NULL; /* no previous in the first round */ - int count=0; - while((count+size) <= DMEM_BLOCKSIZE) { - frag->next = (struct MemFrag *)((char *)frag + size); - frag->prev = prev; - prev = frag; - (char *)frag += size; - count += size; - } - prev->next = NULL; /* the last one has no next struct */ -} - -/*************************************************************************** - * - * dmalloc_initialize(); - * - * Call before the first dmalloc(). Inits a few memory things. - * - **************************************************************************/ -void dmalloc_initialize(void) -{ - unsigned int i; - /* Setup the nmax and fragsize fields of the top structs */ - for(i=0; i< sizeof(qinfo)/sizeof(qinfo[0]); i++) { - top[i].fragsize = qinfo[i]; - top[i].nmax = DMEM_BLOCKSIZE/qinfo[i]; - -#ifdef PSOS - /* for some reason, these aren't nulled from start: */ - top[i].chain = NULL; /* no BLOCKS */ - top[i].nfree = 0; /* no FRAGMENTS */ -#endif -#ifdef SEMAPHORE - { - char name[7]; - snprintf(name, 7, "MEM%d", i); - SEMAPHORECREATE(name, top[i].semaphore_id); - /* doesn't matter if it failed, we continue anyway ;-( */ - } -#endif - } -} - -/**************************************************************************** - * - * fragfromblock() - * - * This should return a fragment from the block and mark it as used - * accordingly. - * - ***************************************************************************/ - -static void *fragfromblock(struct MemBlock *block) -{ - /* make frag point to the first free FRAGMENT */ - struct MemFrag *frag = block->first; - struct MemInfo *mem = (struct MemInfo *)frag; - - /* - * Remove the FRAGMENT from the list and decrease the free counters. - */ - block->first = frag->next; /* new first free FRAGMENT */ - - block->nfree--; /* BLOCK counter */ - block->top->nfree--; /* TOP counter */ - - /* heal the FRAGMENT list */ - if(frag->prev) { - frag->prev->next = frag->next; - } - if(frag->next) { - frag->next->prev = frag->prev; - } - mem->block = block; /* no block bit set here */ - - return ((char *)mem)+sizeof(struct MemInfo); -} - -/*************************************************************************** - * - * dmalloc() - * - * This needs no explanation. A malloc() look-alike. - * - **************************************************************************/ - -void *malloc(size_t size) -{ - void *mem; - - DBG(("malloc(%d)\n", size)); - - /* First, we make room for the space needed in every allocation */ - size += sizeof(struct MemInfo); - - if(size < DMEM_LARGESTSIZE) { - /* get a FRAGMENT */ - - struct MemBlock *block=NULL; /* SAFE */ - struct MemBlock *newblock=NULL; /* SAFE */ - struct MemTop *memtop=NULL; /* SAFE */ - - /* Determine which queue to use */ - unsigned int queue; - for(queue=0; size > qinfo[queue]; queue++) - ; - do { - /* This is the head master of our chain: */ - memtop = &top[queue]; - - DBG(("Top info: CHAIN %p FREE %d MAX %d FRAGSIZE %d\n", - memtop->chain, - memtop->nfree, - memtop->nmax, - memtop->fragsize)); - -#ifdef SEMAPHORE - if(SEMAPHOREOBTAIN(memtop->semaphore_id)) - return NULL; /* failed somehow */ -#endif - - /* get the first BLOCK in the chain */ - block = memtop->chain; - - /* check if we have a free FRAGMENT */ - if(memtop->nfree) { - /* there exists a free FRAGMENT in this chain */ - - /**** We'd prefer to not have this loop here! ****/ - - /* search for the free FRAGMENT */ - while(!block->nfree) - block = block->next; /* check next BLOCK */ - - /* - * Now 'block' is the first BLOCK with a free FRAGMENT - */ - - mem = fragfromblock(block); - - } - else { - /* we do *not* have a free FRAGMENT but need to get us a new - * BLOCK */ - - DMEM_OSALLOCMEM(DMEM_BLOCKSIZE + sizeof(struct MemBlock), - newblock, - struct MemBlock *); - if(!newblock) { - if(++queue < sizeof(qinfo)/sizeof(qinfo[0])) { - /* There are queues for bigger FRAGMENTS that we - * should check before we fail this for real */ -#ifdef DEBUG_VERBOSE - printf("*** " __FILE__ " Trying a bigger Q: %d\n", - queue); -#endif - mem = NULL; - } - else { - dmalloc_failed(size- sizeof(struct MemInfo)); - return NULL; /* not enough memory */ - } - } - else { - /* allocation of big BLOCK was successful */ - MEMINCR(newblock, DMEM_BLOCKSIZE + - sizeof(struct MemBlock)); - - memtop->chain = newblock; /* attach this BLOCK to the - chain */ - newblock->next = block; /* point to the previous first - BLOCK */ - if(block) - block->prev = newblock; /* point back on this new - BLOCK */ - newblock->prev = NULL; /* no previous */ - newblock->top = memtop; /* our head master */ - - /* point to the new first FRAGMENT */ - newblock->first = (struct MemFrag *) - ((char *)newblock+sizeof(struct MemBlock)); - - /* create FRAGMENTS of the BLOCK: */ - FragBlock((char *)newblock->first, memtop->fragsize); - - /* fix the nfree counters */ - newblock->nfree = memtop->nmax; - memtop->nfree += memtop->nmax; - - /* get a FRAGMENT from the BLOCK */ - mem = fragfromblock(newblock); - } - } -#ifdef SEMAPHORE - SEMAPHORERETURN(memtop->semaphore_id); /* let it go */ -#endif - } while(NULL == mem); /* if we should retry a larger FRAGMENT */ - } - else { - /* get a stand-alone BLOCK */ - struct MemInfo *meminfo; - - if(size&1) - /* don't leave this with an odd size since we'll use that bit for - information */ - size++; - - DMEM_OSALLOCMEM(size, meminfo, struct MemInfo *); - - if(meminfo) { - MEMINCR(meminfo, size); - meminfo->block = (void *)(size|BLOCK_BIT); - mem = (char *)meminfo + sizeof(struct MemInfo); - } - else { - dmalloc_failed(size); - mem = NULL; - } - } - return (void *)mem; -} - -/*************************************************************************** - * - * dfree() - * - * This needs no explanation. A free() look-alike. - * - **************************************************************************/ - -void free(void *memp) -{ - struct MemInfo *meminfo = (struct MemInfo *) - ((char *)memp- sizeof(struct MemInfo)); - - DBG(("free(%p)\n", memp)); - - if(!((size_t)meminfo->block&BLOCK_BIT)) { - /* this is a FRAGMENT we have to deal with */ - - struct MemBlock *block=meminfo->block; - struct MemTop *memtop = block->top; - -#ifdef SEMAPHORE - SEMAPHOREOBTAIN(memtop->semaphore_id); -#endif - - /* increase counters */ - block->nfree++; - memtop->nfree++; - - /* is this BLOCK completely empty now? */ - if(block->nfree == memtop->nmax) { - /* yes, return the BLOCK to the system */ - if(block->prev) - block->prev->next = block->next; - else - memtop->chain = block->next; - if(block->next) - block->next->prev = block->prev; - - memtop->nfree -= memtop->nmax; /* total counter subtraction */ - MEMDECR(block, DMEM_BLOCKSIZE + sizeof(struct MemBlock)); - DMEM_OSFREEMEM((void *)block); /* return the whole block */ - } - else { - /* there are still used FRAGMENTS in the BLOCK, link this one - into the chain of free ones */ - struct MemFrag *frag = (struct MemFrag *)meminfo; - frag->prev = NULL; - frag->next = block->first; - if(block->first) - block->first->prev = frag; - block->first = frag; - } -#ifdef SEMAPHORE - SEMAPHORERETURN(memtop->semaphore_id); -#endif - } - else { - /* big stand-alone block, just give it back to the OS: */ - - /* clean BLOCK_BIT */ - MEMDECR(meminfo->block, (size_t)meminfo->block&~BLOCK_BIT); - DMEM_OSFREEMEM((void *)meminfo); - } -} - -/*************************************************************************** - * - * drealloc() - * - * This needs no explanation. A realloc() look-alike. - * - **************************************************************************/ - -void *realloc(void *ptr, size_t size) -{ - struct MemInfo *meminfo = (struct MemInfo *) - ((char *)ptr- sizeof(struct MemInfo)); - /* - * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * NOTE: the ->size field of the meminfo will now contain the MemInfo - * struct size too! - * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - void *mem=NULL; /* SAFE */ - size_t prevsize; - - /* NOTE that this is only valid if BLOCK_BIT isn't set: */ - struct MemBlock *block; - - DBG(("realloc(%p, %d)\n", ptr, size)); - - if(NULL == ptr) - return malloc( size ); - - block = meminfo->block; - - /* Here we check if this is a FRAGMENT and if the new size is - still smaller than the fragsize for this block. */ - if(!((size_t)block&BLOCK_BIT) && - (size + sizeof(struct MemInfo) < block->top->fragsize )) { - - prevsize = block->top->fragsize; - /* This is a FRAGMENT and new size is possible to retain within the - same FRAGMENT */ - if((prevsize > qinfo[0]) && - /* this is not the smallest memory Q */ - (size < (block->top-1)->fragsize)) - /* This fits in a smaller fragment, so we will make a realloc - here */ - ; - else - mem = ptr; /* Just return the same pointer as we got in. */ - } - if(!mem) { - if((size_t)meminfo->block&BLOCK_BIT) { - /* This is a stand-alone BLOCK */ - prevsize = ((size_t)meminfo->block&~BLOCK_BIT) - - sizeof(struct MemInfo); - } - else - /* a FRAGMENT realloc that no longer fits within the same FRAGMENT - * or one that fits in a smaller */ - prevsize = block->top->fragsize; - - /* No tricks involved here, just grab a new bite of memory, copy the - * data from the old place and free the old memory again. */ - mem = malloc(size); - if(mem) { - memcpy(mem, ptr, MIN(size, prevsize) ); - free(ptr); - } - } - return mem; -} - -/*************************************************************************** - * - * dcalloc() - * - * This needs no explanation. A calloc() look-alike. - * - **************************************************************************/ -/* Allocate an array of NMEMB elements each SIZE bytes long. - The entire array is initialized to zeros. */ -void * -calloc (size_t nmemb, size_t size) -{ - void *result = malloc (nmemb * size); - - if (result != NULL) - memset (result, 0, nmemb * size); - - return result; -} |