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!

Reply via email to