forked from len0rd/rockbox
Another pdbox patch by Wincent Balin (FS #10416): switch to using TLSF as memory allocator. Probably the last patch I commit for him, next changes are for him :)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22017 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0d9b7ec73e
commit
840cd10692
21 changed files with 125 additions and 2357 deletions
|
@ -2,13 +2,13 @@ pdbox.c
|
|||
pdbox-net.c
|
||||
pdbox-func.c
|
||||
|
||||
dbestfit-3.3/bmalloc.c
|
||||
dbestfit-3.3/bysize.c
|
||||
dbestfit-3.3/dmalloc.c
|
||||
TLSF-2.4.4/src/tlsf.c
|
||||
/*
|
||||
wfirstfit.c
|
||||
*/
|
||||
|
||||
PDa/src/s_audio_rockbox.c
|
||||
|
||||
|
||||
PDa/src/g_canvas.c
|
||||
PDa/src/g_graph.c
|
||||
PDa/src/g_text.c
|
||||
|
@ -130,7 +130,7 @@ PDa/intern/vline~.c
|
|||
PDa/intern/vsnapshot~.c
|
||||
PDa/intern/wrap~.c
|
||||
|
||||
PDa/extra/OSCroute.c
|
||||
/* PDa/extra/OSCroute.c */
|
||||
PDa/extra/bandpass.c
|
||||
/* PDa/extra/dumpOSC.c Does not compile, file handling stuff */
|
||||
PDa/extra/equalizer.c
|
||||
|
|
|
@ -164,8 +164,14 @@
|
|||
#define PAGE_SIZE (getpagesize())
|
||||
#endif
|
||||
|
||||
#if defined(ROCKBOX) && defined(SIMULATOR) || !defined(ROCKBOX)
|
||||
int printf(char*, ...);
|
||||
#define PRINT_MSG(fmt, args...) printf(fmt, ## args)
|
||||
#define ERROR_MSG(fmt, args...) printf(fmt, ## args)
|
||||
#else
|
||||
#define PRINT_MSG(fmt, args...)
|
||||
#define ERROR_MSG(fmt, args...)
|
||||
#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 */
|
||||
|
@ -567,6 +573,9 @@ size_t get_used_size(void *mem_pool)
|
|||
#if TLSF_STATISTIC
|
||||
return ((tlsf_t *) mem_pool)->used_size;
|
||||
#else
|
||||
#ifdef ROCKBOX
|
||||
(void) mem_pool;
|
||||
#endif /* ROCKBOX */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -578,6 +587,9 @@ size_t get_max_size(void *mem_pool)
|
|||
#if TLSF_STATISTIC
|
||||
return ((tlsf_t *) mem_pool)->max_size;
|
||||
#else
|
||||
#ifdef ROCKBOX
|
||||
(void) mem_pool;
|
||||
#endif /* ROCKBOX */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
Changes
|
||||
|
||||
* (March 30 2005) Daniel
|
||||
|
||||
Linus Nielsen Feltzing provided a patch that corrected several minor problems
|
||||
that prevented dbestfit from working good. Linus also tested and timed
|
||||
dbestfit for real in a target where he replaced the pSOS-provided memory
|
||||
subsystem.
|
||||
|
||||
* 3.2
|
||||
|
||||
Made eons ago, all older changes have been forgotten.
|
|
@ -1,15 +0,0 @@
|
|||
/bysize.c
|
||||
/bysize.h
|
||||
/bmalloc.c
|
||||
/bmalloc.h
|
||||
/dmalloc.c
|
||||
/dmalloc.h
|
||||
/FILES
|
||||
/README
|
||||
/Makefile
|
||||
/Malloc.c
|
||||
/mytest.c
|
||||
/dmytest.c
|
||||
/thoughts
|
||||
/malloc.man
|
||||
/CHANGES
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
OBJS1 = bmalloc.o bysize.o mytest.o
|
||||
TARGET1 = mytest
|
||||
|
||||
OBJS2 = dmalloc.o bmalloc.o bysize.o Malloc.o
|
||||
TARGET2 = mtest
|
||||
|
||||
OBJS3 = dmalloc.o bmalloc.o bysize.o dmytest.o
|
||||
TARGET3 = dmytest
|
||||
|
||||
CFLAGS = -g -DUNIX -DBMALLOC -Wall -pedantic -DDEBUG
|
||||
CC = gcc
|
||||
|
||||
all: $(TARGET1) $(TARGET2) $(TARGET3)
|
||||
|
||||
$(TARGET1): $(OBJS1)
|
||||
$(CC) -g -o $(TARGET1) $(OBJS1)
|
||||
|
||||
$(TARGET2): $(OBJS2)
|
||||
$(CC) -g -o $(TARGET2) $(OBJS2)
|
||||
|
||||
$(TARGET3): $(OBJS3)
|
||||
$(CC) -g -o $(TARGET3) $(OBJS3)
|
||||
|
||||
bmalloc.o: bmalloc.c
|
||||
dmalloc.o: dmalloc.c
|
||||
mytest.o: mytest.c
|
||||
dmytest.o: dmytest.c
|
||||
Malloc.o : Malloc.c
|
||||
bysize.o : bysize.c
|
||||
|
||||
tgz:
|
||||
@(dir=`pwd`;name=`basename $$dir`;echo Creates $$name.tar.gz; cd .. ; \
|
||||
tar -cf $$name.tar `cat $$name/FILES | sed "s:^/:$$name/:g"` ; \
|
||||
gzip $$name.tar ; chmod a+r $$name.tar.gz ; mv $$name.tar.gz $$name/)
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ $(TARGET1) $(TARGET2) $(TARGET3)
|
|
@ -1,200 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Storleken på allokeringen bestäms genom att först slumpas en position i
|
||||
"size_table" ut, sedan slumpas en storlek mellan den postionen och nästa värde
|
||||
i tabellen. Genom att ha tabellen koncentrerad med låga värden, så skapas
|
||||
flest såna. Rutinen håller på tills minnet en allokeringen nekas. Den kommer
|
||||
aldrig att ha mer än MAXIMAL_MEMORY_TO_ALLOCATE allokerat samtidigt. Maximalt
|
||||
har den MAX_ALLOCATIONS allokeringar samtidigt.
|
||||
|
||||
Statistiskt sätt så kommer efter ett tag MAX_ALLOCATIONS/2 allokeringar finnas
|
||||
samtidigt, med varje allokering i median med värdet av halva "size_table".
|
||||
|
||||
När minnet är slut (malloc()=NULL), frågas användaren om han ska fortsätta.
|
||||
|
||||
Med jämna mellanrum skrivs statisktik ut på skärmen. (DISPLAY_WHEN)
|
||||
|
||||
För att stressa systemet med fler små allokeringar, så kan man öka
|
||||
MAX_ALLOCATIONS. AMOUNT_OF_MEMORY bör få den att slå i taket fortare om man
|
||||
minskar det.
|
||||
|
||||
Ingen initiering görs av slumptalen, så allt är upprepbart (men plocka bort
|
||||
kommentaren på srand() och det löser sig.
|
||||
|
||||
*/
|
||||
|
||||
/*#undef BMALLOC*/
|
||||
|
||||
#ifdef BMALLOC
|
||||
#include "dmalloc.h"
|
||||
|
||||
#include "bmalloc.h"
|
||||
#endif
|
||||
|
||||
#define MAX_ALLOCATIONS 100000
|
||||
#define AMOUNT_OF_MEMORY 180000 /* bytes */
|
||||
#define MAXIMAL_MEMORY_TO_ALLOCATE 100000 /* Sätt den här högre än
|
||||
AMOUNT_OF_MEMORY, och malloc() bör
|
||||
returnera NULL förr eller senare */
|
||||
|
||||
#define DISPLAY_WHEN (123456) /* When to display statistic */
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define BOOL char
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
typedef struct {
|
||||
char *memory;
|
||||
long size;
|
||||
char filled_with;
|
||||
long table_position;
|
||||
} MallocStruct;
|
||||
|
||||
/*
|
||||
Skapar en lista med MAX_ALLOCATIONS storlek där det slumpvis allokeras
|
||||
eller reallokeras i.
|
||||
*/
|
||||
|
||||
MallocStruct my_mallocs[MAX_ALLOCATIONS];
|
||||
|
||||
long size_table[]={5,8,10,11,12,14,16,18,20,26,33,50,70,90,120,150,200,400,800,1000,2000,4000,8000,10000,11000,12000,13000,14000,15000,16000,17000,18000};
|
||||
#define TABLESIZE ((sizeof(size_table)-1)/sizeof(long))
|
||||
long size_allocs[TABLESIZE];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
long count=-1;
|
||||
long count_free=0, count_malloc=0, count_realloc=0;
|
||||
long total_memory=0;
|
||||
BOOL out_of_memory=FALSE;
|
||||
unsigned int seed = time( NULL );
|
||||
|
||||
#ifdef BMALLOC
|
||||
void *thisisourheap;
|
||||
thisisourheap = (malloc)(AMOUNT_OF_MEMORY);
|
||||
if(!thisisourheap)
|
||||
return -1; /* can't get memory */
|
||||
add_pool(thisisourheap, AMOUNT_OF_MEMORY);
|
||||
#endif
|
||||
|
||||
seed = 1109323906;
|
||||
|
||||
srand( seed ); /* Initialize randomize */
|
||||
|
||||
printf("seed: %d\n", seed);
|
||||
|
||||
while (!out_of_memory) {
|
||||
long number=rand()%MAX_ALLOCATIONS;
|
||||
long size;
|
||||
long table_position=rand()%TABLESIZE;
|
||||
char fill_with=rand()&255;
|
||||
|
||||
count++;
|
||||
|
||||
size=rand()%(size_table[table_position+1]-size_table[table_position])+size_table[table_position];
|
||||
|
||||
/* fprintf(stderr, "number %d size %d\n", number, size); */
|
||||
|
||||
if (my_mallocs[number].size) { /* Om allokering redan finns på den här
|
||||
positionen, så reallokerar vi eller
|
||||
friar. */
|
||||
long old_size=my_mallocs[number].size;
|
||||
if (my_mallocs[number].size && fill_with<40) {
|
||||
free(my_mallocs[number].memory);
|
||||
total_memory -= my_mallocs[number].size;
|
||||
count_free++;
|
||||
size_allocs[my_mallocs[number].table_position]--;
|
||||
size=0;
|
||||
my_mallocs[number].size = 0;
|
||||
my_mallocs[number].memory = NULL;
|
||||
} else {
|
||||
/*
|
||||
* realloc() part
|
||||
*
|
||||
*/
|
||||
char *temp;
|
||||
#if 0
|
||||
if(my_mallocs[number].size > size) {
|
||||
printf("*** %d is realloc()ed to %d\n",
|
||||
my_mallocs[number].size, size);
|
||||
}
|
||||
#endif
|
||||
if (total_memory-old_size+size>MAXIMAL_MEMORY_TO_ALLOCATE)
|
||||
goto output; /* for-loop */
|
||||
temp = (char *)realloc(my_mallocs[number].memory, size);
|
||||
if (!temp)
|
||||
out_of_memory=TRUE;
|
||||
else {
|
||||
my_mallocs[number].memory = temp;
|
||||
|
||||
my_mallocs[number].size=size;
|
||||
size_allocs[my_mallocs[number].table_position]--;
|
||||
size_allocs[table_position]++;
|
||||
total_memory -= old_size;
|
||||
total_memory += size;
|
||||
old_size=min(old_size, size);
|
||||
while (--old_size>0) {
|
||||
if (my_mallocs[number].memory[old_size]!=my_mallocs[number].filled_with)
|
||||
fprintf(stderr, "Wrong filling!\n");
|
||||
}
|
||||
count_realloc++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (total_memory+size>MAXIMAL_MEMORY_TO_ALLOCATE) {
|
||||
goto output; /* for-loop */
|
||||
}
|
||||
my_mallocs[number].memory=(char *)malloc(size); /* Allokera! */
|
||||
if (!my_mallocs[number].memory)
|
||||
out_of_memory=TRUE;
|
||||
else {
|
||||
size_allocs[table_position]++;
|
||||
count_malloc++;
|
||||
total_memory += size;
|
||||
}
|
||||
}
|
||||
|
||||
if(!out_of_memory) {
|
||||
my_mallocs[number].table_position=table_position;
|
||||
my_mallocs[number].size=size;
|
||||
my_mallocs[number].filled_with=fill_with;
|
||||
memset(my_mallocs[number].memory, fill_with, size);
|
||||
}
|
||||
output:
|
||||
if (out_of_memory || !(count%DISPLAY_WHEN)) {
|
||||
printf("(%d) malloc %d, realloc %d, free %d, total size %d\n", count, count_malloc, count_realloc, count_free, total_memory);
|
||||
{
|
||||
int count;
|
||||
printf("[size bytes]=[number of allocations]\n");
|
||||
for (count=0; count<TABLESIZE; count++) {
|
||||
printf("%ld=%ld, ", size_table[count], size_allocs[count]);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
}
|
||||
if (out_of_memory) {
|
||||
fprintf(stderr, "Memory is out! Continue (y/n)");
|
||||
switch (getchar()) {
|
||||
case 'y':
|
||||
case 'Y':
|
||||
out_of_memory=FALSE;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
for(i = 0;i < MAX_ALLOCATIONS;i++) {
|
||||
if((my_mallocs[i].memory))
|
||||
free(my_mallocs[i].memory);
|
||||
}
|
||||
|
||||
print_lists();
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
Package: dbestfit - a dynamic memory allocator
|
||||
Date: March 30, 2005
|
||||
Version: 3.3
|
||||
Author: Daniel Stenberg <daniel@haxx.se>
|
||||
|
||||
I wrote the dmalloc part for small allocation sizes to improve the behavior
|
||||
of the built-in (first-fit) allocator found in pSOS (around 1996).
|
||||
|
||||
I wrote the bmalloc part (best-fit with splay-tree sorting) just for the fun
|
||||
of it and to see how good malloc() clone I could make. The quality of my
|
||||
implementation is still left to be judged in real-world tests.
|
||||
|
||||
TODO:
|
||||
* Remove the final not-so-very-nice loop in dmalloc.c that checks for a block
|
||||
with free fragments (when the list gets longer too much time might be spent
|
||||
in that loop).
|
||||
|
||||
* Add semaphore protection in bmalloc.
|
||||
|
||||
* Make a separate application that samples the memory usage of a program
|
||||
and is capable of replaying it (in order to test properly).
|
|
@ -1,371 +0,0 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Big (best-fit) Memory Allocation
|
||||
*
|
||||
* Author: Daniel Stenberg
|
||||
* Date: March 5, 1997
|
||||
* Version: 2.0
|
||||
* Email: Daniel.Stenberg@sth.frontec.se
|
||||
*
|
||||
*
|
||||
* Read 'thoughts' for theories and details in implementation.
|
||||
*
|
||||
* Routines meant to replace the most low level functions of an Operting
|
||||
* System
|
||||
*
|
||||
* v2.0
|
||||
* - Made all size-routines get moved out from this file. This way, the size
|
||||
* functions can much more easily get replaced.
|
||||
* - Improved how new memory blocks get added to the size-sorted list. When
|
||||
* not adding new pools, there should never ever be any list traversing
|
||||
* since all information is dynamically gathered.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bysize.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#define BMEM_ALIGN 64 /* resolution */
|
||||
|
||||
#define BMEMERR_TOOSMALL -1
|
||||
|
||||
/* this struct will be stored in all CHUNKS and AREAS */
|
||||
struct BlockInfo {
|
||||
struct BlockInfo *lower; /* previous block in memory (lower address) */
|
||||
struct BlockInfo *higher; /* next block in memory (higher address) */
|
||||
unsigned long info; /* 31 bits size: 1 bit free boolean */
|
||||
#define INFO_FREE 1
|
||||
#define INFO_SIZE (~ INFO_FREE) /* inverted FREE bit pattern */
|
||||
|
||||
/* FREE+SIZE Could be written to use ordinary bitfields if using a smart
|
||||
(like gcc) compiler in a manner like:
|
||||
int size:31;
|
||||
int free:1;
|
||||
|
||||
The 'higher' pointer COULD be removed completely if the size is used as
|
||||
an index to the higher one. This would then REQUIRE the entire memory
|
||||
pool to be contiguous and it needs a 'terminating' "node" or an extra
|
||||
flag that informs about the end of the list.
|
||||
*/
|
||||
};
|
||||
|
||||
/* the BLOCK list should be sorted in a lower to higher address order */
|
||||
struct BlockInfo *blockHead=NULL; /* nothing from the start */
|
||||
|
||||
void print_lists(void);
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* remove_block()
|
||||
*
|
||||
* Remove the block from the address-sorted list.
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
void remove_block(struct BlockInfo *block)
|
||||
{
|
||||
if(block->lower)
|
||||
block->lower->higher = block->higher;
|
||||
else
|
||||
blockHead = block->higher;
|
||||
if(block->higher)
|
||||
block->higher->lower = block->lower;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* add_blocktolists()
|
||||
*
|
||||
* Adds the specified block at the specified place in the address-sorted
|
||||
* list and at the appropriate place in the size-sorted.
|
||||
*
|
||||
***************************************************************************/
|
||||
void add_blocktolists(struct BlockInfo *block,
|
||||
struct BlockInfo *newblock,
|
||||
size_t newsize)
|
||||
{
|
||||
struct BlockInfo *temp; /* temporary storage variable */
|
||||
if(block) {
|
||||
/* `block' is now a lower address than 'newblock' */
|
||||
|
||||
/*
|
||||
* Check if the new CHUNK is wall-to-wall with the lower addressed
|
||||
* one (if *that* is free)
|
||||
*/
|
||||
if(block->info&INFO_FREE) {
|
||||
if((char *)block + (block->info&INFO_SIZE) == (char *)newblock) {
|
||||
/* yes sir, this is our lower address neighbour, enlarge that one
|
||||
pick it out from the list and recursively add that chunk and
|
||||
then we escape */
|
||||
|
||||
/* remove from size-sorted list: */
|
||||
remove_chunksize((char*)block+sizeof(struct BlockInfo));
|
||||
|
||||
block->info += newsize; /* newsize is an even number and thus the FREE
|
||||
bit is untouched */
|
||||
|
||||
remove_block(block); /* unlink the block address-wise */
|
||||
|
||||
/* recursively check our lower friend(s) */
|
||||
add_blocktolists(block->lower, block, block->info&INFO_SIZE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
temp = block->higher;
|
||||
|
||||
block->higher = newblock;
|
||||
newblock->lower = block;
|
||||
newblock->higher = temp;
|
||||
if(newblock->higher)
|
||||
newblock->higher->lower = newblock;
|
||||
}
|
||||
else {
|
||||
/* this block should preceed the heading one */
|
||||
temp = blockHead;
|
||||
|
||||
/* check if this is our higher addressed neighbour */
|
||||
if((char *)newblock + newsize == (char *)temp) {
|
||||
|
||||
/* yes, we are wall-to-wall with the higher CHUNK */
|
||||
if(temp->info&INFO_FREE) {
|
||||
/* and the neighbour is even free, remove that one and enlarge
|
||||
ourselves, call add_pool() recursively and then escape */
|
||||
|
||||
remove_block(temp); /* unlink 'temp' from list */
|
||||
|
||||
/* remove from size-sorted list: */
|
||||
remove_chunksize((char*)temp+sizeof(struct BlockInfo) );
|
||||
|
||||
/* add the upper block's size on ourselves */
|
||||
newsize += temp->info&INFO_SIZE;
|
||||
|
||||
/* add the new, bigger block */
|
||||
add_blocktolists(block, newblock, newsize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
blockHead = newblock;
|
||||
newblock->higher = temp;
|
||||
newblock->lower = NULL; /* there is no lower one */
|
||||
if(newblock->higher)
|
||||
newblock->higher->lower = newblock;
|
||||
}
|
||||
|
||||
newblock->info = newsize | INFO_FREE; /* we do assume size isn't using the
|
||||
FREE bit */
|
||||
insert_bysize((char *)newblock+sizeof(struct BlockInfo), newsize);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* findblockbyaddr()
|
||||
*
|
||||
* Find the block that is just before the input block in memory. Returns NULL
|
||||
* if none is.
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
static struct BlockInfo *findblockbyaddr(struct BlockInfo *block)
|
||||
{
|
||||
struct BlockInfo *test = blockHead;
|
||||
struct BlockInfo *lower = NULL;
|
||||
|
||||
while(test && (test < block)) {
|
||||
lower = test;
|
||||
test = test->higher;
|
||||
}
|
||||
return lower;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* add_pool()
|
||||
*
|
||||
* This function should be the absolutely first function to call. It sets up
|
||||
* the memory bounds of the [first] CHUNK(s). It should be possible to call
|
||||
* this function several times to add more CHUNKs to the pool of free
|
||||
* memory. This allows the bmalloc system to deal with a non-contigous memory
|
||||
* area.
|
||||
*
|
||||
* Returns non-zero if an error occured. The memory was not added then.
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
int add_pool(void *start,
|
||||
size_t size)
|
||||
{
|
||||
struct BlockInfo *newblock = (struct BlockInfo *)start;
|
||||
struct BlockInfo *block;
|
||||
|
||||
if(size < BMEM_ALIGN)
|
||||
return BMEMERR_TOOSMALL;
|
||||
|
||||
block = findblockbyaddr( newblock );
|
||||
/* `block' is now a lower address than 'newblock' or NULL */
|
||||
|
||||
if(size&1)
|
||||
size--; /* only add even sizes */
|
||||
|
||||
add_blocktolists(block, newblock, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
static void bmalloc_failed(size_t size)
|
||||
{
|
||||
printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
|
||||
print_lists();
|
||||
}
|
||||
#else
|
||||
#define bmalloc_failed(x)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
void print_lists()
|
||||
{
|
||||
struct BlockInfo *block = blockHead;
|
||||
#if 1
|
||||
printf("List of BLOCKS (in address order):\n");
|
||||
while(block) {
|
||||
printf(" START %p END %p SIZE %ld FLAG %s\n",
|
||||
(char *)block,
|
||||
(char *)block+(block->info&INFO_SIZE), block->info&INFO_SIZE,
|
||||
(block->info&INFO_FREE)?"free":"used");
|
||||
block = block->higher;
|
||||
}
|
||||
printf("End of BLOCKS:\n");
|
||||
#endif
|
||||
print_sizes();
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
void *bmalloc(size_t size)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static int count=0;
|
||||
int realsize = size + sizeof(struct BlockInfo);
|
||||
if(realsize%4096)
|
||||
realsize = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN;
|
||||
printf("%d bmalloc(%d) [%d]\n", count++, size, realsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
size += sizeof(struct BlockInfo); /* add memory for our header */
|
||||
|
||||
if(size&(BMEM_ALIGN-1)) /* a lot faster than %BMEM_ALIGN but this MUST be
|
||||
changed if the BLOCKSIZE is not 2^X ! */
|
||||
size = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN; /* align like this */
|
||||
|
||||
/* get a CHUNK from the list with this size */
|
||||
mem = obtainbysize ( size );
|
||||
if(mem) {
|
||||
/* the memory block we have got is the "best-fit" and it is already
|
||||
un-linked from the free list */
|
||||
|
||||
/* now do the math to get the proper block pointer */
|
||||
struct BlockInfo *block= (struct BlockInfo *)
|
||||
((char *)mem - sizeof(struct BlockInfo));
|
||||
|
||||
block->info &= ~INFO_FREE;
|
||||
/* not free anymore */
|
||||
|
||||
if( size != (block->info&INFO_SIZE)) {
|
||||
/* split this chunk into two pieces and return the one that fits us */
|
||||
size_t othersize = (block->info&INFO_SIZE) - size;
|
||||
|
||||
if(othersize > BMEM_ALIGN) {
|
||||
/* prevent losing small pieces of memory due to weird alignments
|
||||
of the memory pool */
|
||||
|
||||
block->info = size; /* set new size (leave FREE bit cleared) */
|
||||
|
||||
/* Add the new chunk to the lists: */
|
||||
add_blocktolists(block,
|
||||
(struct BlockInfo *)((char *)block + size),
|
||||
othersize );
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the memory our parent may use: */
|
||||
return (char *)block+sizeof(struct BlockInfo);
|
||||
}
|
||||
else {
|
||||
bmalloc_failed(size);
|
||||
return NULL; /* can't find any memory, fail hard */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bfree(void *ptr)
|
||||
{
|
||||
struct BlockInfo *block = (struct BlockInfo *)
|
||||
((char *)ptr - sizeof(struct BlockInfo));
|
||||
size_t size;
|
||||
|
||||
/* setup our initial higher and lower pointers */
|
||||
struct BlockInfo *lower = block->lower;
|
||||
struct BlockInfo *higher = block->higher;
|
||||
|
||||
#ifdef DEBUG
|
||||
static int freecount=0;
|
||||
printf("%d bfree(%p)\n", freecount++, ptr);
|
||||
#endif
|
||||
|
||||
/* bind together lower addressed FREE CHUNKS */
|
||||
if(lower && (lower->info&INFO_FREE) &&
|
||||
((char *)lower + (lower->info&INFO_SIZE) == (char *)block)) {
|
||||
size = block->info&INFO_SIZE; /* original size */
|
||||
|
||||
/* remove from size-link: */
|
||||
remove_chunksize((char *)lower+sizeof(struct BlockInfo));
|
||||
|
||||
remove_block(block); /* unlink from address list */
|
||||
block = lower; /* new base area pointer */
|
||||
block->info += size; /* append the new size (the FREE bit
|
||||
will remain untouched) */
|
||||
|
||||
lower = lower->lower; /* new lower pointer */
|
||||
}
|
||||
/* bind together higher addressed FREE CHUNKS */
|
||||
if(higher && (higher->info&INFO_FREE) &&
|
||||
((char *)block + (block->info&INFO_SIZE) == (char *)higher)) {
|
||||
/* append higher size, the FREE bit won't be affected */
|
||||
block->info += (higher->info&INFO_SIZE);
|
||||
|
||||
/* unlink from size list: */
|
||||
remove_chunksize((char *)higher+sizeof(struct BlockInfo));
|
||||
remove_block(higher); /* unlink from address list */
|
||||
higher = higher->higher; /* the new higher link */
|
||||
block->higher = higher; /* new higher link */
|
||||
}
|
||||
block->info |= INFO_FREE; /* consider this FREE! */
|
||||
|
||||
block->lower = lower;
|
||||
block->higher = higher;
|
||||
|
||||
insert_bysize((char *)block+sizeof(struct BlockInfo), block->info&INFO_SIZE);
|
||||
|
||||
#ifdef DEBUG
|
||||
print_lists();
|
||||
#endif
|
||||
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
int add_pool(void *start, size_t size);
|
||||
void print_lists(void);
|
||||
|
||||
void *bmalloc(size_t size);
|
||||
void bfree(void *ptr);
|
|
@ -1,428 +0,0 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Size-sorted list/tree functions.
|
||||
*
|
||||
* Author: Daniel Stenberg
|
||||
* Date: March 7, 1997
|
||||
* Version: 2.0
|
||||
* Email: Daniel.Stenberg@sth.frontec.se
|
||||
*
|
||||
*
|
||||
* v2.0
|
||||
* - Added SPLAY TREE functionality.
|
||||
*
|
||||
* Adds and removes CHUNKS from a list or tree.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SPLAY /* we use the splay version as that is much faster */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef SPLAY /* these routines are for the non-splay version */
|
||||
|
||||
struct ChunkInfo {
|
||||
struct ChunkInfo *larger;
|
||||
struct ChunkInfo *smaller;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* the CHUNK list anchor */
|
||||
struct ChunkInfo *chunkHead=NULL;
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
findchunkbysize()
|
||||
|
||||
Find the chunk that is smaller than the input size. Returns
|
||||
NULL if none is.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
static struct ChunkInfo *findchunkbysize(size_t size)
|
||||
{
|
||||
struct ChunkInfo *test = chunkHead;
|
||||
struct ChunkInfo *smaller = NULL;
|
||||
while(test && (test->size < size)) {
|
||||
smaller = test;
|
||||
test = test->larger;
|
||||
}
|
||||
return smaller;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
remove_chunksize()
|
||||
|
||||
Remove the chunk from the size-sorted list.
|
||||
***********************************************************************/
|
||||
|
||||
void remove_chunksize(void *data)
|
||||
{
|
||||
struct ChunkInfo *chunk = (struct ChunkInfo *)data;
|
||||
if(chunk->smaller)
|
||||
chunk->smaller->larger = chunk->larger;
|
||||
else {
|
||||
/* if this has no smaller, this is the head */
|
||||
chunkHead = chunk->larger; /* new head */
|
||||
}
|
||||
if(chunk->larger)
|
||||
chunk->larger->smaller = chunk->smaller;
|
||||
}
|
||||
|
||||
void insert_bysize(char *data, size_t size)
|
||||
{
|
||||
struct ChunkInfo *newchunk = (struct ChunkInfo *)data;
|
||||
struct ChunkInfo *chunk = findchunkbysize ( size );
|
||||
|
||||
newchunk->size = size;
|
||||
|
||||
if(chunk) {
|
||||
/* 'chunk' is smaller than size, append the new chunk ahead of this */
|
||||
newchunk->smaller = chunk;
|
||||
newchunk->larger = chunk->larger;
|
||||
if(chunk->larger)
|
||||
chunk->larger->smaller = newchunk;
|
||||
chunk->larger = newchunk;
|
||||
}
|
||||
else {
|
||||
/* smallest CHUNK around, append first in the list */
|
||||
newchunk->larger = chunkHead;
|
||||
newchunk->smaller = NULL;
|
||||
|
||||
if(chunkHead)
|
||||
chunkHead->smaller = newchunk;
|
||||
chunkHead = newchunk;
|
||||
}
|
||||
}
|
||||
|
||||
char *obtainbysize( size_t size)
|
||||
{
|
||||
struct ChunkInfo *chunk = findchunkbysize( size );
|
||||
|
||||
if(!chunk) {
|
||||
if(size <= (chunkHead->size))
|
||||
/* there is no smaller CHUNK, use the first one (if we fit within that)
|
||||
*/
|
||||
chunk = chunkHead;
|
||||
}
|
||||
else
|
||||
/* we're on the last CHUNK that is smaller than requested, step onto
|
||||
the bigger one */
|
||||
chunk = chunk->larger;
|
||||
|
||||
if(chunk) {
|
||||
remove_chunksize( chunk ); /* unlink size-wise */
|
||||
return (char *)chunk;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_sizes(void)
|
||||
{
|
||||
struct ChunkInfo *chunk = chunkHead;
|
||||
printf("List of CHUNKS (in size order):\n");
|
||||
#if 1
|
||||
while(chunk) {
|
||||
printf(" START %p END %p SIZE %d\n",
|
||||
chunk, (char *)chunk+chunk->size, chunk->size);
|
||||
chunk = chunk->larger;
|
||||
}
|
||||
#endif
|
||||
printf("End of CHUNKS:\n");
|
||||
}
|
||||
|
||||
#else /* Here follows all routines dealing with the SPLAY TREES */
|
||||
|
||||
typedef struct tree_node Tree;
|
||||
struct tree_node {
|
||||
Tree *smaller; /* smaller node */
|
||||
Tree *larger; /* larger node */
|
||||
Tree *same; /* points to a node with identical key */
|
||||
int key; /* the "sort" key */
|
||||
};
|
||||
|
||||
Tree *chunkHead = NULL; /* the root */
|
||||
|
||||
#define compare(i,j) ((i)-(j))
|
||||
|
||||
/* Set this to a key value that will *NEVER* appear otherwise */
|
||||
#define KEY_NOTUSED -1
|
||||
|
||||
/*
|
||||
* Splay using the key i (which may or may not be in the tree.) The starting
|
||||
* root is t. Weight fields are maintained.
|
||||
*/
|
||||
Tree * splay (int i, Tree *t)
|
||||
{
|
||||
Tree N, *l, *r, *y;
|
||||
int comp;
|
||||
|
||||
if (t == NULL)
|
||||
return t;
|
||||
N.smaller = N.larger = NULL;
|
||||
l = r = &N;
|
||||
|
||||
for (;;) {
|
||||
comp = compare(i, t->key);
|
||||
if (comp < 0) {
|
||||
if (t->smaller == NULL)
|
||||
break;
|
||||
if (compare(i, t->smaller->key) < 0) {
|
||||
y = t->smaller; /* rotate smaller */
|
||||
t->smaller = y->larger;
|
||||
y->larger = t;
|
||||
|
||||
t = y;
|
||||
if (t->smaller == NULL)
|
||||
break;
|
||||
}
|
||||
r->smaller = t; /* link smaller */
|
||||
r = t;
|
||||
t = t->smaller;
|
||||
}
|
||||
else if (comp > 0) {
|
||||
if (t->larger == NULL)
|
||||
break;
|
||||
if (compare(i, t->larger->key) > 0) {
|
||||
y = t->larger; /* rotate larger */
|
||||
t->larger = y->smaller;
|
||||
y->smaller = t;
|
||||
t = y;
|
||||
if (t->larger == NULL)
|
||||
break;
|
||||
}
|
||||
l->larger = t; /* link larger */
|
||||
l = t;
|
||||
t = t->larger;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l->larger = r->smaller = NULL;
|
||||
|
||||
l->larger = t->smaller; /* assemble */
|
||||
r->smaller = t->larger;
|
||||
t->smaller = N.larger;
|
||||
t->larger = N.smaller;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Insert key i into the tree t. Return a pointer to the resulting tree or
|
||||
NULL if something went wrong. */
|
||||
Tree *insert(int i, Tree *t, Tree *new)
|
||||
{
|
||||
if (new == NULL) {
|
||||
return t;
|
||||
}
|
||||
|
||||
if (t != NULL) {
|
||||
t = splay(i,t);
|
||||
if (compare(i, t->key)==0) {
|
||||
/* it already exists one of this size */
|
||||
|
||||
new->same = t;
|
||||
new->key = i;
|
||||
new->smaller = t->smaller;
|
||||
new->larger = t->larger;
|
||||
|
||||
t->smaller = new;
|
||||
t->key = KEY_NOTUSED;
|
||||
|
||||
return new; /* new root node */
|
||||
}
|
||||
}
|
||||
|
||||
if (t == NULL) {
|
||||
new->smaller = new->larger = NULL;
|
||||
}
|
||||
else if (compare(i, t->key) < 0) {
|
||||
new->smaller = t->smaller;
|
||||
new->larger = t;
|
||||
t->smaller = NULL;
|
||||
}
|
||||
else {
|
||||
new->larger = t->larger;
|
||||
new->smaller = t;
|
||||
t->larger = NULL;
|
||||
}
|
||||
new->key = i;
|
||||
|
||||
new->same = NULL; /* no identical node (yet) */
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Finds and deletes the best-fit node from the tree. Return a pointer to the
|
||||
resulting tree. best-fit means the smallest node that fits the requested
|
||||
size. */
|
||||
Tree *removebestfit(int i, Tree *t, Tree **removed)
|
||||
{
|
||||
Tree *x;
|
||||
|
||||
if (t==NULL)
|
||||
return NULL;
|
||||
t = splay(i,t);
|
||||
if(compare(i, t->key) > 0) {
|
||||
/* too small node, try the larger chain */
|
||||
if(t->larger)
|
||||
t=splay(t->larger->key, t);
|
||||
else {
|
||||
/* fail */
|
||||
*removed = NULL;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
if (compare(i, t->key) <= 0) { /* found it */
|
||||
|
||||
/* FIRST! Check if there is a list with identical sizes */
|
||||
x = t->same;
|
||||
if(x) {
|
||||
/* there is, pick one from the list */
|
||||
|
||||
/* 'x' is the new root node */
|
||||
|
||||
x->key = t->key;
|
||||
x->larger = t->larger;
|
||||
x->smaller = t->smaller;
|
||||
*removed = t;
|
||||
return x; /* new root */
|
||||
}
|
||||
|
||||
if (t->smaller == NULL) {
|
||||
x = t->larger;
|
||||
}
|
||||
else {
|
||||
x = splay(i, t->smaller);
|
||||
x->larger = t->larger;
|
||||
}
|
||||
*removed = t;
|
||||
|
||||
return x;
|
||||
}
|
||||
else {
|
||||
*removed = NULL; /* no match */
|
||||
return t; /* It wasn't there */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Deletes the node we point out from the tree if it's there. Return a pointer
|
||||
to the resulting tree. */
|
||||
Tree *removebyaddr(Tree *t, Tree *remove)
|
||||
{
|
||||
Tree *x;
|
||||
|
||||
if (!t || !remove)
|
||||
return NULL;
|
||||
|
||||
if(KEY_NOTUSED == remove->key) {
|
||||
/* just unlink ourselves nice and quickly: */
|
||||
remove->smaller->same = remove->same;
|
||||
if(remove->same)
|
||||
remove->same->smaller = remove->smaller;
|
||||
/* voila, we're done! */
|
||||
return t;
|
||||
}
|
||||
|
||||
t = splay(remove->key,t);
|
||||
|
||||
/* Check if there is a list with identical sizes */
|
||||
|
||||
x = t->same;
|
||||
if(x) {
|
||||
/* 'x' is the new root node */
|
||||
|
||||
x->key = t->key;
|
||||
x->larger = t->larger;
|
||||
x->smaller = t->smaller;
|
||||
|
||||
return x; /* new root */
|
||||
}
|
||||
|
||||
/* Remove the actualy root node: */
|
||||
|
||||
if (t->smaller == NULL) {
|
||||
x = t->larger;
|
||||
}
|
||||
else {
|
||||
x = splay(remove->key, t->smaller);
|
||||
x->larger = t->larger;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int printtree(Tree * t, int d, char output)
|
||||
{
|
||||
int distance=0;
|
||||
Tree *node;
|
||||
int i;
|
||||
if (t == NULL)
|
||||
return 0;
|
||||
distance += printtree(t->larger, d+1, output);
|
||||
for (i=0; i<d; i++)
|
||||
if(output)
|
||||
printf(" ");
|
||||
|
||||
if(output) {
|
||||
printf("%d[%d]", t->key, i);
|
||||
}
|
||||
|
||||
for(node = t->same; node; node = node->same) {
|
||||
distance += i; /* this has the same "virtual" distance */
|
||||
|
||||
if(output)
|
||||
printf(" [+]");
|
||||
}
|
||||
if(output)
|
||||
puts("");
|
||||
|
||||
distance += i;
|
||||
distance += printtree(t->smaller, d+1, output);
|
||||
return distance;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* Here follow the look-alike interface so that the tree-function names are
|
||||
the same as the list-ones to enable easy interchange */
|
||||
|
||||
void remove_chunksize(void *data)
|
||||
{
|
||||
chunkHead = removebyaddr(chunkHead, data);
|
||||
}
|
||||
|
||||
void insert_bysize(char *data, size_t size)
|
||||
{
|
||||
chunkHead = insert(size, chunkHead, (Tree *)data);
|
||||
}
|
||||
|
||||
char *obtainbysize( size_t size)
|
||||
{
|
||||
Tree *receive;
|
||||
chunkHead = removebestfit(size, chunkHead, &receive);
|
||||
return (char *)receive;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void print_sizes(void)
|
||||
{
|
||||
printtree(chunkHead, 0, 1);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
void remove_chunksize(void *data);
|
||||
void insert_bysize(char *data, size_t size);
|
||||
char *obtainbysize( size_t size);
|
||||
void print_sizes(void);
|
|
@ -1,711 +0,0 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Dynamic Memory Allocation
|
||||
*
|
||||
* Author: Daniel Stenberg
|
||||
* Date: March 10, 1997
|
||||
* Version: 2.3
|
||||
* Email: Daniel.Stenberg@sth.frontec.se
|
||||
*
|
||||
*
|
||||
* Read 'thoughts' for theories and details of this implementation.
|
||||
*
|
||||
* v2.1
|
||||
* - I once again managed to gain some memory. BLOCK allocations now only use
|
||||
* a 4 bytes header (instead of previos 8) just as FRAGMENTS.
|
||||
*
|
||||
* v2.2
|
||||
* - Re-adjusted the fragment sizes to better fit into the somewhat larger
|
||||
* block.
|
||||
*
|
||||
* v2.3
|
||||
* - Made realloc(NULL, size) work as it should. Which is like a malloc(size)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef ROCKBOX
|
||||
#include "plugin.h"
|
||||
#define memset rb->memset
|
||||
#define memcpy rb->memcpy
|
||||
#else /* ROCKBOX */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif /* ROCKBOX */
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#ifdef PSOS
|
||||
#include <psos.h>
|
||||
#define SEMAPHORE /* the PSOS routines use semaphore protection */
|
||||
#else
|
||||
#include <stdlib.h> /* makes the PSOS complain on the 'size_t' typedef */
|
||||
#endif
|
||||
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#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++) { a=4064/i; if(a*i >= 4060) { if(i%4==0) {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.
|
||||
*/
|
||||
|
||||
#if defined(BIGBLOCKS) && BIGBLOCKS==4060 /* previously */
|
||||
#ifdef ROCKBOX
|
||||
unsigned
|
||||
#endif /* ROCKBOX */
|
||||
short qinfo[]= { 20, 28, 52, 116, 312, 580, 812, 2028 };
|
||||
#else
|
||||
#ifdef ROCKBOX
|
||||
unsigned
|
||||
#endif /* ROCKBOX */
|
||||
short qinfo[]= { 20, 28, 52, 116, 312, 580, 1016, 2032};
|
||||
/* 52 and 312 only make use of 4056 bytes, but without them there are too
|
||||
wide gaps */
|
||||
#endif
|
||||
|
||||
#ifndef ROCKBOX
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#endif /* ROCKBOX */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Globals */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* keeper of the chain of BLOCKS */
|
||||
static struct MemTop top[ sizeof(qinfo)/sizeof(qinfo[0]) ];
|
||||
|
||||
/* are we experienced? */
|
||||
static char initialized = 0;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Start of the real code */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
#ifdef DEBUG
|
||||
/************
|
||||
* A few functions that are verbose and tells us about the current status
|
||||
* of the dmalloc system
|
||||
***********/
|
||||
|
||||
static void dmalloc_status()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#define BORDER 1200
|
||||
|
||||
void *dbgmalloc(int size)
|
||||
{
|
||||
char *mem;
|
||||
size += BORDER;
|
||||
#ifdef PSOS
|
||||
rn_getseg(0,size,RN_NOWAIT,0,(void **)&mem);
|
||||
#else
|
||||
mem = malloc(size);
|
||||
#endif
|
||||
if(mem) {
|
||||
memset(mem, 0xaa, BORDER/2);
|
||||
memset(mem+BORDER/2, 0xbb, size -BORDER);
|
||||
memset(mem-BORDER/2+size, 0xcc, BORDER/2);
|
||||
*(long *)mem = size;
|
||||
mem += (BORDER/2);
|
||||
}
|
||||
printf("OSmalloc(%p)\n", mem);
|
||||
return (void *)mem;
|
||||
}
|
||||
|
||||
void checkmem(char *ptr)
|
||||
{
|
||||
int i;
|
||||
long size;
|
||||
ptr -= BORDER/2;
|
||||
|
||||
for(i=4; i<(BORDER/2); i++)
|
||||
if((unsigned char)ptr[i] != 0xaa) {
|
||||
printf("########### ALERT ALERT\n");
|
||||
break;
|
||||
}
|
||||
size = *(long *)ptr;
|
||||
for(i=size-1; i>=(size - BORDER/2); i--)
|
||||
if((unsigned char)ptr[i] != 0xcc) {
|
||||
printf("********* POST ALERT\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dbgfree(char *ptr)
|
||||
{
|
||||
long size;
|
||||
checkmem(ptr);
|
||||
ptr -= BORDER/2;
|
||||
size = *(long *)ptr;
|
||||
|
||||
printf("OSfree(%ld)\n", size);
|
||||
#ifdef PSOS
|
||||
rn_retseg(0, ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#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) {
|
||||
memp += size;
|
||||
frag->next = (struct MemFrag *)memp;
|
||||
frag->prev = prev;
|
||||
prev = frag;
|
||||
frag = frag->next;
|
||||
count += size;
|
||||
}
|
||||
prev->next = NULL; /* the last one has no next struct */
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* initialize();
|
||||
*
|
||||
* Called in the first dmalloc(). Inits a few memory things.
|
||||
*
|
||||
**************************************************************************/
|
||||
static void initialize(void)
|
||||
{
|
||||
#ifdef ROCKBOX
|
||||
unsigned
|
||||
#endif /* ROCKBOX */
|
||||
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];
|
||||
sprintf(name, "MEM%d", i);
|
||||
SEMAPHORECREATE(name, top[i].semaphore_id);
|
||||
/* doesn't matter if it failed, we continue anyway ;-( */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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 *dmalloc(size_t size)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
DBG(("dmalloc(%d)\n", size));
|
||||
|
||||
if(!initialized)
|
||||
initialize();
|
||||
|
||||
/* 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 */
|
||||
#ifdef ROCKBOX
|
||||
unsigned
|
||||
#endif /* ROCKBOX */
|
||||
int queue;
|
||||
|
||||
for(queue=0; size > qinfo[queue]; queue++)
|
||||
;
|
||||
do {
|
||||
/* This is the head master of our chain: */
|
||||
memtop = &top[queue];
|
||||
|
||||
DBG(("Top info: %p %d %d %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 */
|
||||
|
||||
/* I WANT THIS LOOP OUT OF 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
|
||||
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);
|
||||
|
||||
#if defined(DEBUG) && !defined(BMALLOC)
|
||||
checkmem((char *)newblock);
|
||||
#endif
|
||||
|
||||
/* 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 dfree(void *memp)
|
||||
{
|
||||
struct MemInfo *meminfo = (struct MemInfo *)
|
||||
((char *)memp- sizeof(struct MemInfo));
|
||||
|
||||
DBG(("dfree(%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: */
|
||||
MEMDECR(&meminfo->block, (size_t)meminfo->block&~BLOCK_BIT); /* clean BLOCK_BIT */
|
||||
DMEM_OSFREEMEM((void *)meminfo);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* drealloc()
|
||||
*
|
||||
* This needs no explanation. A realloc() look-alike.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
void *drealloc(char *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 = 0;
|
||||
|
||||
/* NOTE that this is only valid if BLOCK_BIT isn't set: */
|
||||
struct MemBlock *block;
|
||||
|
||||
DBG(("drealloc(%p, %d)\n", ptr, size));
|
||||
|
||||
if(NULL == ptr)
|
||||
return dmalloc( size );
|
||||
|
||||
block = meminfo->block;
|
||||
|
||||
if(!((size_t)meminfo->block&BLOCK_BIT) &&
|
||||
(size + sizeof(struct MemInfo) <
|
||||
(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 Q */
|
||||
;
|
||||
else
|
||||
mem = ptr; /* Just return the same pointer as we got in. */
|
||||
}
|
||||
if(!mem) {
|
||||
/* This is a stand-alone BLOCK or a realloc that no longer fits within
|
||||
the same FRAGMENT */
|
||||
|
||||
if((size_t)meminfo->block&BLOCK_BIT) {
|
||||
prevsize = ((size_t)meminfo->block&~BLOCK_BIT) -
|
||||
sizeof(struct MemInfo);
|
||||
}
|
||||
else
|
||||
prevsize -= sizeof(struct MemInfo);
|
||||
|
||||
/* 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 = dmalloc(size);
|
||||
if(mem) {
|
||||
memcpy(mem, ptr, MIN(size, prevsize) );
|
||||
dfree(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 *
|
||||
dcalloc (size_t nmemb, size_t size)
|
||||
{
|
||||
void *result = dmalloc (nmemb * size);
|
||||
|
||||
if (result != NULL)
|
||||
memset (result, 0, nmemb * size);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
void *dmalloc(size_t);
|
||||
void dfree(void *);
|
||||
void *drealloc(void *, size_t);
|
||||
|
||||
#define malloc(x) dmalloc(x)
|
||||
#define free(x) dfree(x)
|
||||
#define realloc(x,y) drealloc(x,y)
|
||||
|
||||
#ifdef ROCKBOX
|
||||
void *dcalloc(size_t, size_t);
|
||||
#define calloc(x,y) dcalloc(x,y)
|
||||
#endif
|
|
@ -1,138 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dmalloc.h"
|
||||
|
||||
#define MAX 500
|
||||
#define MAX2 1000
|
||||
#define MAXC 2
|
||||
|
||||
#define TESTA
|
||||
#define TESTB
|
||||
#define TESTC
|
||||
#define TESTD
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int memory = 0;
|
||||
|
||||
#ifdef BMALLOC
|
||||
#define HEAP 10000
|
||||
void *heap = (malloc)(HEAP);
|
||||
if(!heap)
|
||||
return -1;
|
||||
add_pool(heap, HEAP);
|
||||
#endif
|
||||
|
||||
{
|
||||
#define MAXK 100
|
||||
void *wow[MAXK];
|
||||
wow[0]=malloc(700);
|
||||
realloc(wow[0], 680);
|
||||
return 0;
|
||||
|
||||
for(i=0; i<MAXK; i++)
|
||||
if(!(wow[i]=malloc(412))) {
|
||||
printf("*** Couldn't allocated memory, exiting\n");
|
||||
return -2;
|
||||
}
|
||||
for(i=MAXK-1; i>=0; i-=2)
|
||||
free(wow[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TESTD
|
||||
{
|
||||
#define MAXS 10
|
||||
#define MAXS1 0
|
||||
void *ptr[MAXS];
|
||||
|
||||
for(i=MAXS1; i< MAXS; i++) {
|
||||
printf("%d malloc(%d)\n", i, i*55);
|
||||
ptr[i] = malloc (i*55);
|
||||
}
|
||||
for(i=MAXS1; i< MAXS; i++) {
|
||||
void *tmp;
|
||||
printf("%d realloc(%d)\n", i, i*155);
|
||||
tmp=realloc(ptr[i], i*155);
|
||||
if(tmp)
|
||||
ptr[i] = tmp;
|
||||
}
|
||||
for(i=MAXS1; i< MAXS; i++) {
|
||||
printf("%d free(%d)\n", i, i*155);
|
||||
free(ptr[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TESTC
|
||||
{
|
||||
void *ptr[MAXC];
|
||||
printf("This is test C:\n");
|
||||
|
||||
for(i=0; i< MAXC; i++) {
|
||||
printf("%d malloc(100)\n", i+1);
|
||||
ptr[i] = malloc(100);
|
||||
printf(" ...returned %p\n", ptr[i]);
|
||||
}
|
||||
|
||||
for(i=0; i< MAXC; i++) {
|
||||
printf("%d free()\n", i+1);
|
||||
free(ptr[i]);
|
||||
}
|
||||
|
||||
printf("End of test C:\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TESTA
|
||||
{
|
||||
void *pointers[MAX];
|
||||
printf("This is test I:\n");
|
||||
|
||||
for(i=0; i<MAX; i++) {
|
||||
printf("%d attempts malloc(%d)\n", i, i*6);
|
||||
pointers[i]=malloc(i*6);
|
||||
if(!pointers[i]) {
|
||||
printf("cant get more memory!");
|
||||
return(0);
|
||||
}
|
||||
memory += (i*6);
|
||||
}
|
||||
printf("\namount: %d\n", memory);
|
||||
memory = 0;
|
||||
for(i=0; i<MAX; i++) {
|
||||
printf("%d attempts realloc(%d)\n", i, i*7);
|
||||
pointers[i]=realloc(pointers[i], i*7);
|
||||
memory += i*7;
|
||||
}
|
||||
printf("\namount: %d\n", memory);
|
||||
for(i=0; i<MAX; i++) {
|
||||
printf("%d attempts free(%d)\n", i, i*7);
|
||||
free(pointers[i]);
|
||||
}
|
||||
printf("\nend of test 1\n");
|
||||
}
|
||||
#endif
|
||||
#ifdef TESTB
|
||||
{
|
||||
void *pointers2[MAX2];
|
||||
memory = 0;
|
||||
printf("\nTest II\n");
|
||||
for(i=0; i< MAX2; i++) {
|
||||
/* printf("%d attempts malloc(%d)\n", i, 7); */
|
||||
pointers2[i] = malloc(7);
|
||||
memory += 7;
|
||||
}
|
||||
printf("\namount: %d\n", memory);
|
||||
for(i=0; i< MAX2; i++) {
|
||||
free(pointers2[i]);
|
||||
}
|
||||
printf("\nend of test II\n");
|
||||
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
MALLOC(3V) C LIBRARY FUNCTIONS MALLOC(3V)
|
||||
|
||||
|
||||
NAME
|
||||
malloc, free, realloc, calloc
|
||||
|
||||
SYNOPSIS
|
||||
#include <malloc.h>
|
||||
|
||||
void *malloc(size)
|
||||
size_t size;
|
||||
|
||||
void free(ptr)
|
||||
void *ptr;
|
||||
|
||||
void *realloc(ptr, size)
|
||||
void *ptr;
|
||||
size_t size;
|
||||
|
||||
void *calloc(nelem, elsize)
|
||||
size_t nelem;
|
||||
size_t elsize;
|
||||
|
||||
DESCRIPTION
|
||||
These routines provide a general-purpose memory allocation
|
||||
package. They maintain a table of free blocks for efficient
|
||||
allocation and coalescing of free storage. When there is no
|
||||
suitable space already free, the allocation routines call
|
||||
rn_getseg() to get more memory from the system.
|
||||
|
||||
Each of the allocation routines returns a pointer to space
|
||||
suitably aligned for storage of any type of object. Each
|
||||
returns a NULL pointer if the request cannot be completed
|
||||
(see DIAGNOSTICS).
|
||||
|
||||
malloc() returns a pointer to a block of at least size
|
||||
bytes, which is appropriately aligned.
|
||||
|
||||
free() releases a previously allocated block. Its argument
|
||||
is a pointer to a block previously allocated by malloc(),
|
||||
calloc() or realloc().
|
||||
|
||||
realloc() changes the size of the block referenced by ptr to
|
||||
size bytes and returns a pointer to the (possibly moved)
|
||||
block. The contents will be unchanged up to the lesser of
|
||||
the new and old sizes. If unable to honor a reallocation
|
||||
request, realloc() leaves its first argument unaltered.
|
||||
|
||||
**** DMALLOC DOES NOT COMPLY WITH THE PARAGRAPH BELOW ****
|
||||
|
||||
For backwards compatibility, realloc() accepts a pointer to a
|
||||
block freed since the most recent call to malloc(), cal-
|
||||
loc() or realloc().
|
||||
|
||||
Note: using realloc() with a block freed before the most recent
|
||||
call to malloc(), calloc() or realloc() is an error.
|
||||
|
||||
calloc() uses malloc() to allocate space for an array of
|
||||
nelem elements of size elsize, initializes the space to
|
||||
zeros, and returns a pointer to the initialized block. The
|
||||
block should be freed with free().
|
||||
|
||||
|
||||
malloc() and realloc() return a non- NULL pointer if size is 0,
|
||||
and calloc() returns a non-NULL pointer if nelem or elsize is 0,
|
||||
but these pointers should not be dereferenced.
|
||||
|
||||
Note: Always cast the value returned by malloc(), realloc() or
|
||||
calloc().
|
||||
|
||||
|
||||
RETURN VALUES On success, malloc(), calloc() and realloc() return a
|
||||
pointer to space suitably aligned for storage of any type of
|
||||
object. On failure, they return NULL.
|
||||
|
||||
free() does not return a value.
|
||||
|
||||
|
||||
NOTES
|
||||
Because malloc() and realloc() return a non-NULL pointer if size
|
||||
is 0, and calloc() returns a non-NULL pointer if nelem or elsize
|
||||
is 0, a zero size need not be treated as a special case if it
|
||||
should be passed to these functions unpredictably. Also, the
|
||||
pointer returned by these functions may be passed to subsequent
|
||||
invocations of realloc().
|
||||
|
||||
|
||||
BUGS
|
||||
|
||||
**** DMALLOC DOES NOT COMPLY WITH THE PARAGRAPH BELOW ****
|
||||
|
||||
Since realloc() accepts a pointer to a block freed since the last
|
||||
call to malloc(), calloc() or realloc(), a degradation of
|
||||
performance results. The semantics of free() should be changed
|
||||
so that the contents of a previously freed block are undefined.
|
|
@ -1,69 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bmalloc.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *pointers[5];
|
||||
int i;
|
||||
void *area;
|
||||
|
||||
for(i=0; i<5; i++)
|
||||
pointers[i] = malloc(8000);
|
||||
|
||||
if(argc>1) {
|
||||
switch(argv[1][0]) {
|
||||
case '1':
|
||||
for(i=0; i<5; i++) {
|
||||
add_pool(pointers[i], 4000);
|
||||
add_pool((char *)pointers[i]+4000, 4000);
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
area = malloc(20000);
|
||||
add_pool(area, 3000);
|
||||
add_pool((char *)area+6000, 3000);
|
||||
add_pool((char *)area+3000, 3000);
|
||||
add_pool((char *)area+12000, 3000);
|
||||
add_pool((char *)area+9000, 3000);
|
||||
break;
|
||||
case '3':
|
||||
{
|
||||
void *ptr[10];
|
||||
area = malloc(20000);
|
||||
add_pool(area, 20000);
|
||||
|
||||
printf(" ** TEST USAGE\n");
|
||||
for(i=0; i<9; i++)
|
||||
ptr[i]=bmalloc(200);
|
||||
print_lists();
|
||||
for(i=0; i<9; i++)
|
||||
bfree(ptr[i]);
|
||||
printf(" ** END OF TEST USAGE\n");
|
||||
}
|
||||
|
||||
break;
|
||||
case '4':
|
||||
{
|
||||
void *ptr[10];
|
||||
area = malloc(20000);
|
||||
add_pool(area, 20000);
|
||||
|
||||
ptr[0]=bmalloc(4080);
|
||||
print_lists();
|
||||
bfree(ptr[0]);
|
||||
printf(" ** END OF TEST USAGE\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
for(i=4; i>=0; i--)
|
||||
add_pool(pointers[i], 8000-i*100);
|
||||
|
||||
print_lists();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
=====================================
|
||||
Memory Allocation Algorithm Theories.
|
||||
=====================================
|
||||
|
||||
GOAL
|
||||
It is intended to be a 100% working memory allocation system. It should be
|
||||
capable of replacing an ordinary Operating System's own routines. It should
|
||||
work good in a multitasking, shared memory, non-virtual memory environment
|
||||
without clogging the memory. Primary aimed for small machines, CPUs and
|
||||
memory amounts.
|
||||
|
||||
I use a best-fit algorithm with a slight overhead in order to increase speed
|
||||
a lot. It should remain scalable and work good with very large amount of
|
||||
memory and free/used memory blocks too.
|
||||
|
||||
TERMINOLOGY
|
||||
|
||||
FRAGMENT - small identically sized parts of a larger BLOCK, they are when
|
||||
travered in lists etc _not_ allocated.
|
||||
BLOCK - large memory area, if used for FRAGMENTS, they are linked in a
|
||||
lists. One list for each FRAGMENT size supported.
|
||||
TOP - head struct that holds information about and points to a chain
|
||||
of BLOCKS for a particular FRAGMENT size.
|
||||
CHUNK - a contiguous area of free memory
|
||||
|
||||
MEMORY SYSTEM
|
||||
|
||||
We split the system in two parts. One part allocates small memory amounts
|
||||
and one part allocates large memory amounts, but all allocations are done
|
||||
"through" the small-part-system. There is an option to use only the small
|
||||
system (and thus use the OS for large blocks) or the complete package.
|
||||
|
||||
##############################################################################
|
||||
SMALL SIZE ALLOCATIONS
|
||||
##############################################################################
|
||||
|
||||
Keywords for this system is 'Deferred Coalescing' and 'quick lists'.
|
||||
|
||||
ALLOC
|
||||
|
||||
* Small allocations are "aligned" upwards to a set of preset sizes. In the
|
||||
current implementation I use 20, 28, 52, 116, 312, 580, 812, 2028 bytes.
|
||||
Memory allocations of these sizes are refered to as FRAGMENTS.
|
||||
(The reason for these specific sizes is the requirement that they must be
|
||||
32-bit aligned and fit as good as possible within 4060 bytes.)
|
||||
|
||||
* Allocations larger than 2028 will get a BLOCK for that allocation only.
|
||||
|
||||
* Each of these sizes has it's own TOP. When a FRAGMENT is requested, a
|
||||
larger BLOCK will be allocated and divided into many FRAGMENTS (all of the
|
||||
same size). TOP points to a list with BLOCKS that contains FRAGMENTS of
|
||||
the same size. Each BLOCK has a 'number of free FRAGMENTS' counter and so
|
||||
has each TOP (for the entire chain).
|
||||
|
||||
* A BLOCK is around 4060 bytes plus the size of the information header. This
|
||||
size is adjusted to make the allocation of the big block not require more
|
||||
than 4096 bytes. (This might not be so easy to be sure of, if you don't
|
||||
know how the big-block system works, but the BMALLOC system uses an
|
||||
extra header of 12 bytes and the header for the FRAGMENT BLOCK is 20 bytes
|
||||
in a general 32-bit unix environment.)
|
||||
|
||||
* In case the allocation of a BLOCK fails when a FRAGMENT is required, the
|
||||
next size of FRAGMENTS will be checked for a free FRAGMENT. First when the
|
||||
larger size lists have been tested without success it will fail for real.
|
||||
|
||||
FREE
|
||||
|
||||
* When FRAGMENTS are freed so that a BLOCK becomes non-used, it is returned
|
||||
to the system.
|
||||
|
||||
* FREEing a fragment adds the buffer in a LIFO-order. That means that the
|
||||
next request for a fragment from the same list, the last freed buffer will
|
||||
be returned first.
|
||||
|
||||
REALLOC
|
||||
|
||||
* REALLOCATION of a FRAGMENT does first check if the new size would fit
|
||||
within the same FRAGMENT and if it would use the same FRAGMENT size. If it
|
||||
does and would, the same pointer is returned.
|
||||
|
||||
OVERHEAD
|
||||
|
||||
Yes, there is an overhead on small allocations (internal fragmentation).
|
||||
Yet, I do believe that small allocations more often than larger ones are
|
||||
used dynamically. I believe that a large overhead is not a big problem if it
|
||||
remains only for a while. The big gain is with the extreme speed we can GET
|
||||
and RETURN small allocations. This has yet to be proven. I am open to other
|
||||
systems of dealing with the small ones, but I don`t believe in using the
|
||||
same system for all sizes of allocations.
|
||||
|
||||
IMPROVEMENT
|
||||
|
||||
An addition to the above described algorithm is the `save-empty-BLOCKS-a-
|
||||
while-afterwards`. It will be used when the last used FRAGMENT within a
|
||||
BLOCK is freed. The BLOCK will then not get returned to the system until "a
|
||||
few more" FRAGMENTS have been freed in case the last [few] freed FRAGMENTS
|
||||
are allocated yet again (and thus prevent the huge overhead of making
|
||||
FRAGMENTS in a BLOCK). The "only" drawback of such a SEBAWA concept is
|
||||
that it would mean an even bigger overhead...
|
||||
|
||||
HEADERS (in allocated data)
|
||||
|
||||
FRAGMENTS - 32-bit pointer to its parent BLOCK (lowest bit must be 0)
|
||||
BLOCK - 32-bit size (lowest bit must be 1 to separate this from
|
||||
FRAGMENTS)
|
||||
|
||||
##############################################################################
|
||||
LARGER ALLOCATIONS
|
||||
##############################################################################
|
||||
|
||||
If the requested size is larger than the largest FRAGMENT size supported,
|
||||
the allocation will be made for this memory area alone, or if a BLOCK is
|
||||
allocated to fit lots of FRAGMENTS a large block is also desired.
|
||||
|
||||
* We add memory to the "system" with the add_pool() function call. It
|
||||
specifies the start and size of the new block of memory that will be
|
||||
used in this memory allocation system. Several add_pool() calls are
|
||||
supported and they may or may not add contiguous memory.
|
||||
|
||||
* Make all blocks get allocated aligned to BLOCKSIZE (sometimes referred to
|
||||
as 'grain size'), 64 bytes in my implementation. Reports tell us there is
|
||||
no real gain in increasing the size of the align.
|
||||
|
||||
* We link *all* pieces of memory (AREAS), free or not free. We keep the list
|
||||
in address order and thus when a FREE() occurs we know instanstly if there
|
||||
are FREE CHUNKS wall-to-wall. No list "travels" needed. Requires some
|
||||
extra space in every allocated BLOCK. Still needs to put the new CHUNK in
|
||||
the right place in size-sorted list/tree. All memory areas, allocated or
|
||||
not, contain the following header:
|
||||
- size of this memory area
|
||||
- FREE status
|
||||
- pointer to the next AREA closest in memory
|
||||
- pointer to the prev AREA closest in memory
|
||||
(12 bytes)
|
||||
|
||||
* Sort all FREE CHUNKS in size-order. We use a SPLAY TREE algorithm for
|
||||
maximum speed. Data/structs used for the size-sorting functions are kept
|
||||
in an abstraction layer away from this since it is really not changing
|
||||
anything (except executing speed).
|
||||
|
||||
ALLOC (RSIZE - requested size, aligned properly)
|
||||
|
||||
* Fetch a CHUNK that RSIZE fits within. If the found CHUNK is larger than
|
||||
RSIZE, split it and return the RSIZE to the caller. Link the new CHUNK
|
||||
into the list/tree.
|
||||
|
||||
FREE (AREA - piece of memory that is returned to the system)
|
||||
|
||||
* Since the allocated BLOCK has kept its link-pointers, we can without
|
||||
checking any list instantly see if there are any FREE CHUNKS that are
|
||||
wall-to-wall with the AREA (both sides). If the AREA *is* wall-to-wall
|
||||
with one or two CHUNKS that or they are unlinked from the lists, enlarged
|
||||
and re-linked into the lists.
|
||||
|
||||
REALLOC
|
||||
|
||||
* There IS NO realloc() of large blocks, they are performed in the higher
|
||||
layer (dmalloc).
|
||||
|
||||
|
||||
##############################################################################
|
||||
FURTHER READING
|
||||
##############################################################################
|
||||
|
||||
* "Dynamic Storage Allocation: A Survey and Critical Review" (Paul R. Wilson,
|
||||
Mark S. Johnstone, Michael Neely, David Boles)
|
||||
ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
|
||||
|
||||
* "A Memory Allocator" (Doug Lea)
|
||||
http://g.oswego.edu/dl/html/malloc.html
|
|
@ -2319,12 +2319,12 @@ void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
|
|||
void openit(const char *dirname, const char *filename)
|
||||
{
|
||||
char* nameptr;
|
||||
char* dirbuf = getbytes(MAXPDSTRING);
|
||||
char dirbuf[MAXPDSTRING];
|
||||
|
||||
/* Workaround: If the file resides in the root directory,
|
||||
add a trailing slash to prevent directory part
|
||||
of the filename from being removed -- W.B. */
|
||||
char* ffilename = getbytes(MAXPDSTRING);
|
||||
char ffilename[MAXPDSTRING];
|
||||
ffilename[0] = '/';
|
||||
ffilename[1] = '\0';
|
||||
strcat(ffilename, filename);
|
||||
|
@ -2338,10 +2338,6 @@ void openit(const char *dirname, const char *filename)
|
|||
}
|
||||
else
|
||||
error("%s: can't open", filename);
|
||||
|
||||
/* Clean up. */
|
||||
freebytes(dirbuf, MAXPDSTRING);
|
||||
freebytes(ffilename, MAXPDSTRING);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2374,14 +2370,14 @@ char* rb_getcwd(char* buf, ssize_t size)
|
|||
extern t_namelist* sys_openlist;
|
||||
void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
t_namelist *nl;
|
||||
char cwd[MAXPDSTRING];
|
||||
|
||||
(void) dummy;
|
||||
(void) s;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
t_namelist *nl;
|
||||
char* cwd = getbytes(MAXPDSTRING);
|
||||
|
||||
/* Get current working directory. */
|
||||
rb_getcwd(cwd, MAXPDSTRING);
|
||||
|
||||
|
@ -2391,9 +2387,6 @@ void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
|
|||
|
||||
namelist_free(sys_openlist);
|
||||
sys_openlist = 0;
|
||||
|
||||
/* Clean up. */
|
||||
freebytes(cwd, MAXPDSTRING);
|
||||
}
|
||||
|
||||
/* Fake GUI start. Originally in s_inter.c */
|
||||
|
@ -2405,7 +2398,7 @@ int sys_startgui(const char *guidir)
|
|||
{
|
||||
unsigned int i;
|
||||
t_atom zz[23];
|
||||
char* cmdbuf = getbytes(4*MAXPDSTRING);
|
||||
char cmdbuf[4*MAXPDSTRING];
|
||||
|
||||
(void) guidir;
|
||||
|
||||
|
@ -2420,9 +2413,6 @@ int sys_startgui(const char *guidir)
|
|||
SETFLOAT(zz+22,0);
|
||||
glob_initfromgui(0, 0, 23, zz);
|
||||
|
||||
/* Clean up. */
|
||||
freebytes(cmdbuf, 4*MAXPDSTRING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2436,14 +2426,11 @@ int sys_getblksize(void)
|
|||
/* Find library directory and set it. */
|
||||
void sys_findlibdir(const char* filename)
|
||||
{
|
||||
(void) filename;
|
||||
char sbuf[MAXPDSTRING];
|
||||
|
||||
char* sbuf = getbytes(MAXPDSTRING);
|
||||
(void) filename;
|
||||
|
||||
/* Make current working directory the system library directory. */
|
||||
rb_getcwd(sbuf, MAXPDSTRING);
|
||||
sys_libdir = gensym(sbuf);
|
||||
|
||||
/* Clean up. */
|
||||
freebytes(sbuf, MAXPDSTRING);
|
||||
}
|
||||
|
|
|
@ -58,14 +58,17 @@ rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
|
|||
/* Quit flag. */
|
||||
bool quit = false;
|
||||
|
||||
/* Thread IDs. */
|
||||
unsigned int gui_thread_id;
|
||||
unsigned int time_thread_id;
|
||||
/* Stack sizes for threads. */
|
||||
#define CORESTACKSIZE (8 * 1024 * 1024)
|
||||
#define GUISTACKSIZE (512 * 1024)
|
||||
|
||||
/* Stacks for threads. */
|
||||
#define STACK_SIZE 16384
|
||||
uint32_t gui_stack[STACK_SIZE / sizeof(uint32_t)];
|
||||
uint32_t time_stack[256 / sizeof(uint32_t)];
|
||||
/* Thread stacks. */
|
||||
void* core_stack;
|
||||
void* gui_stack;
|
||||
|
||||
/* Thread IDs. */
|
||||
unsigned int core_thread_id;
|
||||
unsigned int gui_thread_id;
|
||||
|
||||
|
||||
/* GUI thread */
|
||||
|
@ -102,20 +105,33 @@ void gui_thread(void)
|
|||
rb->thread_exit();
|
||||
}
|
||||
|
||||
/* Running time thread. */
|
||||
void time_thread(void)
|
||||
/* Core thread */
|
||||
void core_thread(void)
|
||||
{
|
||||
/* Add the directory the called .pd resides in to lib directories. */
|
||||
sys_findlibdir(filename);
|
||||
|
||||
/* Open the PD design file. */
|
||||
sys_openlist = namelist_append(sys_openlist, filename);
|
||||
|
||||
/* Fake a GUI start. */
|
||||
sys_startgui(NULL);
|
||||
|
||||
/* Core scheduler loop */
|
||||
while(!quit)
|
||||
{
|
||||
/* Add time slice in milliseconds. */
|
||||
runningtime += (1000 / HZ);
|
||||
rb->sleep(1);
|
||||
/* Use sys_send_dacs() function as timer. */
|
||||
while(sys_send_dacs() != SENDDACS_NO)
|
||||
sched_tick(sys_time + sys_time_per_dsp_tick);
|
||||
|
||||
yield();
|
||||
}
|
||||
|
||||
rb->thread_exit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Plug-in entry point */
|
||||
enum plugin_status plugin_start(const void* parameter)
|
||||
{
|
||||
|
@ -133,14 +149,19 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
/* Allocate memory; check it's size; add to the pool. */
|
||||
/* Initialize memory pool. */
|
||||
mem_pool = rb->plugin_get_audio_buffer(&mem_size);
|
||||
if(mem_size < MIN_MEM_SIZE)
|
||||
{
|
||||
rb->splash(HZ, "Not enough memory!");
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
add_pool(mem_pool, mem_size);
|
||||
#if 1
|
||||
init_memory_pool(mem_size, mem_pool);
|
||||
#endif
|
||||
#if 0
|
||||
set_memory_pool(mem_pool, mem_size);
|
||||
#endif
|
||||
|
||||
/* Initialize net. */
|
||||
net_init();
|
||||
|
@ -164,36 +185,36 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
DEFAULTADVANCE, /* Scheduler advance */
|
||||
1 /* Enable */);
|
||||
|
||||
/* Add the directory the called .pd resides in to lib directories. */
|
||||
sys_findlibdir(filename);
|
||||
|
||||
/* Open the parameter file. */
|
||||
sys_openlist = namelist_append(sys_openlist, filename);
|
||||
|
||||
/* Fake a GUI start. */
|
||||
sys_startgui(NULL);
|
||||
/* Create stacks for threads. */
|
||||
core_stack = getbytes(CORESTACKSIZE);
|
||||
gui_stack = getbytes(GUISTACKSIZE);
|
||||
if(core_stack == NULL || gui_stack == NULL)
|
||||
{
|
||||
rb->splash(HZ, "Not enough memory!");
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
/* Start threads. */
|
||||
time_thread_id =
|
||||
rb->create_thread(&time_thread,
|
||||
time_stack,
|
||||
sizeof(time_stack),
|
||||
core_thread_id =
|
||||
rb->create_thread(&core_thread,
|
||||
core_stack,
|
||||
CORESTACKSIZE,
|
||||
0, /* FIXME Which flags? */
|
||||
"PD running time"
|
||||
"PD core"
|
||||
IF_PRIO(, PRIORITY_REALTIME)
|
||||
IF_COP(, COP));
|
||||
|
||||
gui_thread_id =
|
||||
rb->create_thread(&gui_thread,
|
||||
gui_stack,
|
||||
sizeof(gui_stack),
|
||||
GUISTACKSIZE,
|
||||
0, /* FIXME Which flags? */
|
||||
"PD GUI"
|
||||
IF_PRIO(, PRIORITY_USER_INTERFACE)
|
||||
IF_COP(, CPU));
|
||||
|
||||
/* If having an error creating threads, bail out. */
|
||||
if(time_thread_id == 0 || gui_thread_id == 0)
|
||||
if(core_thread_id == 0 || gui_thread_id == 0)
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
/* Initialize scheduler time variables. */
|
||||
|
@ -205,9 +226,8 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
/* Main loop. */
|
||||
while(!quit)
|
||||
{
|
||||
/* Use sys_send_dacs() function as timer. */
|
||||
while(sys_send_dacs() != SENDDACS_NO)
|
||||
sched_tick(sys_time + sys_time_per_dsp_tick);
|
||||
/* Add time slice in milliseconds. */
|
||||
runningtime += (1000 / HZ);
|
||||
|
||||
/* Sleep to the next time slice. */
|
||||
rb->sleep(1);
|
||||
|
@ -215,7 +235,7 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
|
||||
/* Wait for threads to complete. */
|
||||
rb->thread_wait(gui_thread_id);
|
||||
rb->thread_wait(time_thread_id);
|
||||
rb->thread_wait(core_thread_id);
|
||||
|
||||
/* Close audio subsystem. */
|
||||
sys_close_audio();
|
||||
|
@ -223,6 +243,13 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
/* Destroy net. */
|
||||
net_destroy();
|
||||
|
||||
/* Clear memory pool. */
|
||||
#if 1
|
||||
destroy_memory_pool(mem_pool);
|
||||
#endif
|
||||
#if 0
|
||||
clear_memory_pool();
|
||||
#endif
|
||||
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,19 +22,50 @@
|
|||
#ifndef PDBOX_H
|
||||
#define PDBOX_H
|
||||
|
||||
/* Use dbestfit. */
|
||||
#include "bmalloc.h"
|
||||
#include "dmalloc.h"
|
||||
|
||||
#if 1
|
||||
/* Use TLSF. */
|
||||
#include "tlsf.h"
|
||||
#endif
|
||||
|
||||
/* Pure Data */
|
||||
#include "m_pd.h"
|
||||
|
||||
|
||||
/* dbestfit declarations. */
|
||||
|
||||
/* Minimal memory size. */
|
||||
#define MIN_MEM_SIZE (4 * 1024 * 1024)
|
||||
|
||||
/* Memory prototypes. */
|
||||
|
||||
#if 1
|
||||
/* Direct memory allocator functions to TLSF. */
|
||||
#define malloc(size) tlsf_malloc(size)
|
||||
#define free(ptr) tlsf_free(ptr)
|
||||
#define realloc(ptr, size) tlsf_realloc(ptr, size)
|
||||
#define calloc(elements, elem_size) tlsf_calloc(elements, elem_size)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
extern void set_memory_pool(void* memory_pool, size_t memory_size);
|
||||
extern void clear_memory_pool(void);
|
||||
extern void* mcalloc(size_t nmemb, size_t size);
|
||||
extern void* mmalloc(size_t size);
|
||||
extern void mfree(void* ptr);
|
||||
extern void* mrealloc(void* ptr, size_t size);
|
||||
extern void print_memory_pool(void);
|
||||
|
||||
#define malloc mmalloc
|
||||
#define free mfree
|
||||
#define realloc mrealloc
|
||||
#define calloc mcalloc
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#include <stdlib.h>
|
||||
#define malloc malloc
|
||||
#define free free
|
||||
#define realloc realloc
|
||||
#define calloc calloc
|
||||
#endif
|
||||
|
||||
/* Audio declarations. */
|
||||
#define PD_SAMPLERATE 22050
|
||||
|
@ -44,7 +75,7 @@
|
|||
|
||||
/* Audio buffer part. Contains data for one HZ period. */
|
||||
#ifdef SIMULATOR
|
||||
#define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS * 4)
|
||||
#define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS * 32)
|
||||
#else
|
||||
#define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS)
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,7 @@ $(PDBOXBUILDDIR)/pdbox.rock: $(PDBOX_OBJ)
|
|||
PDBOXFLAGS = $(PLUGINFLAGS) \
|
||||
-DFIXEDPOINT -DSTATIC -DPD -DUSEAPI_ROCKBOX \
|
||||
-I$(PDBOXSRCDIR) -I$(PDBOXSRCDIR)/PDa/src \
|
||||
-DBMALLOC -I$(PDBOXSRCDIR)/dbestfit-3.3
|
||||
-I$(PDBOXSRCDIR)/TLSF-2.4.4/src
|
||||
|
||||
# Compile PDBox with extra flags (adapted from ZXBox)
|
||||
$(PDBOXBUILDDIR)/%.o: $(PDBOXSRCDIR)/%.c $(PLUGINBITMAPLIB) $(PDBOXSRCDIR)/pdbox.make
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue