Tobias Heimann wrote:
Hi guys,
I've just started to develop a plugin for rockbox and stumbled over the
memory allocation:
Is there anything like malloc() and free() in rockbox and if yes, which
headers do I have to include for that?
So far, I've only found buffer_alloc() in buffer.h, but that results in
an undefined reference error.
I'm building for the coldfire m68k btw.
Thanks for any help,
Tobias
Tobias,
Having done a fair share of commercial embedded development, I agree
with the general opinion that malloc in an embedded application is not
usually a good idea. It's not really as hard to deal with as you might
imagine though. It just requires a slightly different mindset. Once
you achieve that, it'll be a piece of cake.
Nevertheless, there are times when the best solution to a problem is to
use dynamic memory allocation. However, you often don't need the full
power of malloc/free. As some have pointed out, it's pretty easy to
allocate memory sequentially from a static buffer. The solutions shown
so far don't allow for any amount of free'ing at all however. If you do
need to use a malloc/free cycle as part of your algorithm, perhaps in a
series of nested calls or something similar, there is a fairly simple
extension of the techniques already shown that you can use. I call this
a "mark/release" allocator: it's basically a sequential allocator which
allocates from a static buffer but it allows you to release (free)
memory back to a previously "marked" level. Basically, all of the
sequential allocations since the last mark are free'd in one operation,
allowing that memory to be re-used (in a later nested call, for
example). This is a very efficient technique and, depending on what
you're doing, it can be very effective.
I've typed up the code for this from memory (pasted below). You'll
probably want to do a little testing with it first. ;)
Good luck,
~ray
--------------------------------------------------------------------------
typedef struct tagMRPOOL
{
char *base, *next;
int total, avail;
}
MRPOOL;
void mr_init(MRPOOL *pool, void *mem, int size)
{
pool->base = pool->next = mem;
pool->total = pool->avail = size;
}
int mr_mark(MRPOOL *pool)
{
return (int) pool->next - pool->base;
}
void * mr_alloc(MRPOOL *pool, int size)
{
void *mem = NULL;
if (size <= pool->avail)
{
mem = pool->next;
pool->next += size;
pool->avail -= size;
}
return mem;
}
void mr_release(MRPOOL *pool, int mark)
{
assert( (mark >= 0) && (mark < pool->total) );
pool->next = pool->base + mark;
pool->avail = pool->total - mark;
}
// useful for temporary string copies:
char *mr_strdup(MRPOOL *pool, const char *str)
{
int size = strlen(str) + 1;
char *newstr = mr_alloc(pool, size);
if (newstr)
strcpy(newstr, str);
return newstr;
}
--------------------------------------------------------------------------
Here's a usage example:
extern char static_buffer[];
static MRPOOL pool;
void myalgo()
{
mr_init(&pool, static_buffer, sizeof(static_buffer)); // always init
first!
char *somemem = mr_alloc(&pool, size_needed);
while( some_nested_op() );
// no need to release when top level exits
}
bool some_nested_op()
{
int mark = mr_mark(&pool); // always mark (once) before alloc
char *somemem = mr_alloc(&pool, size_needed);
char *moremem = mr_alloc(&pool, size_needed2);
while( another_nested_op() );
mr_release(&pool, mark); // always release before exit (if did alloc)
return false;
}
bool another_nested_op()
{
int mark = mr_mark(&pool);
char *somemem = mr_alloc(&pool, size_needed);
char *moremem = mr_alloc(&pool, size_needed2);
mr_release(&pool, mark);
return false;
}
--------------------------------------------------------------------------
Note: It's even possible to return dynamic memory from a subroutine so
long as the subroutine doesn't release it before exit. If the
subroutine must release, and the size of the memory to be returned is
known in advance, it can pre-allocate the return buffer before it
'marks'. (Alternately, the caller can allocate the return buffer and
pass it in.)
Hope this is helpful!