1
0
Fork 0
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:
Peter D'Hoye 2009-07-23 21:37:35 +00:00
parent 0d9b7ec73e
commit 840cd10692
21 changed files with 125 additions and 2357 deletions

View file

@ -2,13 +2,13 @@ pdbox.c
pdbox-net.c pdbox-net.c
pdbox-func.c pdbox-func.c
dbestfit-3.3/bmalloc.c TLSF-2.4.4/src/tlsf.c
dbestfit-3.3/bysize.c /*
dbestfit-3.3/dmalloc.c wfirstfit.c
*/
PDa/src/s_audio_rockbox.c PDa/src/s_audio_rockbox.c
PDa/src/g_canvas.c PDa/src/g_canvas.c
PDa/src/g_graph.c PDa/src/g_graph.c
PDa/src/g_text.c PDa/src/g_text.c
@ -130,7 +130,7 @@ PDa/intern/vline~.c
PDa/intern/vsnapshot~.c PDa/intern/vsnapshot~.c
PDa/intern/wrap~.c PDa/intern/wrap~.c
PDa/extra/OSCroute.c /* PDa/extra/OSCroute.c */
PDa/extra/bandpass.c PDa/extra/bandpass.c
/* PDa/extra/dumpOSC.c Does not compile, file handling stuff */ /* PDa/extra/dumpOSC.c Does not compile, file handling stuff */
PDa/extra/equalizer.c PDa/extra/equalizer.c

View file

@ -164,8 +164,14 @@
#define PAGE_SIZE (getpagesize()) #define PAGE_SIZE (getpagesize())
#endif #endif
#if defined(ROCKBOX) && defined(SIMULATOR) || !defined(ROCKBOX)
int printf(char*, ...);
#define PRINT_MSG(fmt, args...) printf(fmt, ## args) #define PRINT_MSG(fmt, args...) printf(fmt, ## args)
#define ERROR_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 int u32_t; /* NOTE: Make sure that this type is 4 bytes long on your computer */
typedef unsigned char u8_t; /* NOTE: Make sure that this type is 1 byte on your computer */ typedef 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 #if TLSF_STATISTIC
return ((tlsf_t *) mem_pool)->used_size; return ((tlsf_t *) mem_pool)->used_size;
#else #else
#ifdef ROCKBOX
(void) mem_pool;
#endif /* ROCKBOX */
return 0; return 0;
#endif #endif
} }
@ -578,6 +587,9 @@ size_t get_max_size(void *mem_pool)
#if TLSF_STATISTIC #if TLSF_STATISTIC
return ((tlsf_t *) mem_pool)->max_size; return ((tlsf_t *) mem_pool)->max_size;
#else #else
#ifdef ROCKBOX
(void) mem_pool;
#endif /* ROCKBOX */
return 0; return 0;
#endif #endif
} }

View file

@ -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.

View file

@ -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

View file

@ -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)

View file

@ -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, skapas
flest såna. Rutinen håller 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 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 skärmen. (DISPLAY_WHEN)
För att stressa systemet med fler små allokeringar, kan man öka
MAX_ALLOCATIONS. AMOUNT_OF_MEMORY bör den att slå i taket fortare om man
minskar det.
Ingen initiering görs av slumptalen, allt är upprepbart (men plocka bort
kommentaren 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, 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;
}

View file

@ -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).

View file

@ -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
}

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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

View file

@ -2319,12 +2319,12 @@ void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
void openit(const char *dirname, const char *filename) void openit(const char *dirname, const char *filename)
{ {
char* nameptr; char* nameptr;
char* dirbuf = getbytes(MAXPDSTRING); char dirbuf[MAXPDSTRING];
/* Workaround: If the file resides in the root directory, /* Workaround: If the file resides in the root directory,
add a trailing slash to prevent directory part add a trailing slash to prevent directory part
of the filename from being removed -- W.B. */ of the filename from being removed -- W.B. */
char* ffilename = getbytes(MAXPDSTRING); char ffilename[MAXPDSTRING];
ffilename[0] = '/'; ffilename[0] = '/';
ffilename[1] = '\0'; ffilename[1] = '\0';
strcat(ffilename, filename); strcat(ffilename, filename);
@ -2338,10 +2338,6 @@ void openit(const char *dirname, const char *filename)
} }
else else
error("%s: can't open", filename); 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; extern t_namelist* sys_openlist;
void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv) void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
{ {
t_namelist *nl;
char cwd[MAXPDSTRING];
(void) dummy; (void) dummy;
(void) s; (void) s;
(void) argc; (void) argc;
(void) argv; (void) argv;
t_namelist *nl;
char* cwd = getbytes(MAXPDSTRING);
/* Get current working directory. */ /* Get current working directory. */
rb_getcwd(cwd, MAXPDSTRING); 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); namelist_free(sys_openlist);
sys_openlist = 0; sys_openlist = 0;
/* Clean up. */
freebytes(cwd, MAXPDSTRING);
} }
/* Fake GUI start. Originally in s_inter.c */ /* Fake GUI start. Originally in s_inter.c */
@ -2405,7 +2398,7 @@ int sys_startgui(const char *guidir)
{ {
unsigned int i; unsigned int i;
t_atom zz[23]; t_atom zz[23];
char* cmdbuf = getbytes(4*MAXPDSTRING); char cmdbuf[4*MAXPDSTRING];
(void) guidir; (void) guidir;
@ -2420,9 +2413,6 @@ int sys_startgui(const char *guidir)
SETFLOAT(zz+22,0); SETFLOAT(zz+22,0);
glob_initfromgui(0, 0, 23, zz); glob_initfromgui(0, 0, 23, zz);
/* Clean up. */
freebytes(cmdbuf, 4*MAXPDSTRING);
return 0; return 0;
} }
@ -2436,14 +2426,11 @@ int sys_getblksize(void)
/* Find library directory and set it. */ /* Find library directory and set it. */
void sys_findlibdir(const char* filename) 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. */ /* Make current working directory the system library directory. */
rb_getcwd(sbuf, MAXPDSTRING); rb_getcwd(sbuf, MAXPDSTRING);
sys_libdir = gensym(sbuf); sys_libdir = gensym(sbuf);
/* Clean up. */
freebytes(sbuf, MAXPDSTRING);
} }

View file

@ -58,14 +58,17 @@ rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
/* Quit flag. */ /* Quit flag. */
bool quit = false; bool quit = false;
/* Thread IDs. */ /* Stack sizes for threads. */
unsigned int gui_thread_id; #define CORESTACKSIZE (8 * 1024 * 1024)
unsigned int time_thread_id; #define GUISTACKSIZE (512 * 1024)
/* Stacks for threads. */ /* Thread stacks. */
#define STACK_SIZE 16384 void* core_stack;
uint32_t gui_stack[STACK_SIZE / sizeof(uint32_t)]; void* gui_stack;
uint32_t time_stack[256 / sizeof(uint32_t)];
/* Thread IDs. */
unsigned int core_thread_id;
unsigned int gui_thread_id;
/* GUI thread */ /* GUI thread */
@ -102,20 +105,33 @@ void gui_thread(void)
rb->thread_exit(); rb->thread_exit();
} }
/* Running time thread. */ /* Core thread */
void time_thread(void) 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) while(!quit)
{ {
/* Add time slice in milliseconds. */ /* Use sys_send_dacs() function as timer. */
runningtime += (1000 / HZ); while(sys_send_dacs() != SENDDACS_NO)
rb->sleep(1); sched_tick(sys_time + sys_time_per_dsp_tick);
yield();
} }
rb->thread_exit(); rb->thread_exit();
} }
/* Plug-in entry point */ /* Plug-in entry point */
enum plugin_status plugin_start(const void* parameter) enum plugin_status plugin_start(const void* parameter)
{ {
@ -133,14 +149,19 @@ enum plugin_status plugin_start(const void* parameter)
return PLUGIN_ERROR; 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); mem_pool = rb->plugin_get_audio_buffer(&mem_size);
if(mem_size < MIN_MEM_SIZE) if(mem_size < MIN_MEM_SIZE)
{ {
rb->splash(HZ, "Not enough memory!"); rb->splash(HZ, "Not enough memory!");
return PLUGIN_ERROR; 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. */ /* Initialize net. */
net_init(); net_init();
@ -164,36 +185,36 @@ enum plugin_status plugin_start(const void* parameter)
DEFAULTADVANCE, /* Scheduler advance */ DEFAULTADVANCE, /* Scheduler advance */
1 /* Enable */); 1 /* Enable */);
/* Add the directory the called .pd resides in to lib directories. */ /* Create stacks for threads. */
sys_findlibdir(filename); core_stack = getbytes(CORESTACKSIZE);
gui_stack = getbytes(GUISTACKSIZE);
/* Open the parameter file. */ if(core_stack == NULL || gui_stack == NULL)
sys_openlist = namelist_append(sys_openlist, filename); {
rb->splash(HZ, "Not enough memory!");
/* Fake a GUI start. */ return PLUGIN_ERROR;
sys_startgui(NULL); }
/* Start threads. */ /* Start threads. */
time_thread_id = core_thread_id =
rb->create_thread(&time_thread, rb->create_thread(&core_thread,
time_stack, core_stack,
sizeof(time_stack), CORESTACKSIZE,
0, /* FIXME Which flags? */ 0, /* FIXME Which flags? */
"PD running time" "PD core"
IF_PRIO(, PRIORITY_REALTIME) IF_PRIO(, PRIORITY_REALTIME)
IF_COP(, COP)); IF_COP(, COP));
gui_thread_id = gui_thread_id =
rb->create_thread(&gui_thread, rb->create_thread(&gui_thread,
gui_stack, gui_stack,
sizeof(gui_stack), GUISTACKSIZE,
0, /* FIXME Which flags? */ 0, /* FIXME Which flags? */
"PD GUI" "PD GUI"
IF_PRIO(, PRIORITY_USER_INTERFACE) IF_PRIO(, PRIORITY_USER_INTERFACE)
IF_COP(, CPU)); IF_COP(, CPU));
/* If having an error creating threads, bail out. */ /* 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; return PLUGIN_ERROR;
/* Initialize scheduler time variables. */ /* Initialize scheduler time variables. */
@ -205,9 +226,8 @@ enum plugin_status plugin_start(const void* parameter)
/* Main loop. */ /* Main loop. */
while(!quit) while(!quit)
{ {
/* Use sys_send_dacs() function as timer. */ /* Add time slice in milliseconds. */
while(sys_send_dacs() != SENDDACS_NO) runningtime += (1000 / HZ);
sched_tick(sys_time + sys_time_per_dsp_tick);
/* Sleep to the next time slice. */ /* Sleep to the next time slice. */
rb->sleep(1); rb->sleep(1);
@ -215,7 +235,7 @@ enum plugin_status plugin_start(const void* parameter)
/* Wait for threads to complete. */ /* Wait for threads to complete. */
rb->thread_wait(gui_thread_id); rb->thread_wait(gui_thread_id);
rb->thread_wait(time_thread_id); rb->thread_wait(core_thread_id);
/* Close audio subsystem. */ /* Close audio subsystem. */
sys_close_audio(); sys_close_audio();
@ -223,6 +243,13 @@ enum plugin_status plugin_start(const void* parameter)
/* Destroy net. */ /* Destroy net. */
net_destroy(); net_destroy();
/* Clear memory pool. */
#if 1
destroy_memory_pool(mem_pool);
#endif
#if 0
clear_memory_pool();
#endif
return PLUGIN_OK; return PLUGIN_OK;
} }

View file

@ -22,19 +22,50 @@
#ifndef PDBOX_H #ifndef PDBOX_H
#define PDBOX_H #define PDBOX_H
/* Use dbestfit. */
#include "bmalloc.h" #if 1
#include "dmalloc.h" /* Use TLSF. */
#include "tlsf.h"
#endif
/* Pure Data */ /* Pure Data */
#include "m_pd.h" #include "m_pd.h"
/* dbestfit declarations. */
/* Minimal memory size. */ /* Minimal memory size. */
#define MIN_MEM_SIZE (4 * 1024 * 1024) #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. */ /* Audio declarations. */
#define PD_SAMPLERATE 22050 #define PD_SAMPLERATE 22050
@ -44,7 +75,7 @@
/* Audio buffer part. Contains data for one HZ period. */ /* Audio buffer part. Contains data for one HZ period. */
#ifdef SIMULATOR #ifdef SIMULATOR
#define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS * 4) #define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS * 32)
#else #else
#define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS) #define AUDIOBUFSIZE (PD_SAMPLES_PER_HZ * PD_OUT_CHANNELS)
#endif #endif

View file

@ -23,7 +23,7 @@ $(PDBOXBUILDDIR)/pdbox.rock: $(PDBOX_OBJ)
PDBOXFLAGS = $(PLUGINFLAGS) \ PDBOXFLAGS = $(PLUGINFLAGS) \
-DFIXEDPOINT -DSTATIC -DPD -DUSEAPI_ROCKBOX \ -DFIXEDPOINT -DSTATIC -DPD -DUSEAPI_ROCKBOX \
-I$(PDBOXSRCDIR) -I$(PDBOXSRCDIR)/PDa/src \ -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) # Compile PDBox with extra flags (adapted from ZXBox)
$(PDBOXBUILDDIR)/%.o: $(PDBOXSRCDIR)/%.c $(PLUGINBITMAPLIB) $(PDBOXSRCDIR)/pdbox.make $(PDBOXBUILDDIR)/%.o: $(PDBOXSRCDIR)/%.c $(PLUGINBITMAPLIB) $(PDBOXSRCDIR)/pdbox.make