Threadsafe Memory allocations in FreeRTOS: Static and dynamic
Dynamic memory allocation in C/C++ can be done using malloc/calloc functions.
When we are done using the memory, we can use free function to free up the memory used.
An embedded system should basically be deterministic in nature. Which means it should be predictable in time domain.
We need to know how much time it would usually take to complete and action in order to call it predictable. Dynamic memory allocation is a run time activity.
Consider the following example:
size_t s = 20000; // s is SIZE
// malloc declaration/initialization
int* ptr = (int*)malloc(s);
// return condition if the memory block is not
// initialized
if (ptr == NULL) {
cout << "Null pointer has been returned";
}
// condition printing the message if the memory is
// initialized
else {
cout << "Memory has been allocated at address "
<< ptr << endl;
}
free(ptr);
Q1) When can a ptr return NULL?
A1) It does not have enough memory to allocate.
Q2) How much time does it take to allocate memory?
A2) Unknown. Hence it is non - deterministic and un predictable!
Recommended by LinkedIn
Q3) I wanted 20000. I have 38000 free but it still allocates a NULL. Why?
A3) Standard malloc function searches for contiguous blocks of memory. Here despite having 38K free memory, it cannot allocate it since it is not contiguous.
Does this mean, we can not allocate dynamic memory in RTOS? How does FreeRTOS overcome this issue?
In order to overcome such issues RTOS have wrappers overriding the standard dynamic memory allocations.
Consider the following wrapper - pvPortMalloc() and vPortFree():
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/*-----------------------------------------------------------*/
void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn;
vTaskSuspendAll();
{
pvReturn = malloc( xWantedSize );
}
xTaskResumeAll();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
if( pv )
{
vTaskSuspendAll();
{
free( pv );
}
xTaskResumeAll();
}
}
In the above code, we can see that the implemenation was made threadsafe by suspending all and resuming tasks after allocation such that it does not effect the memory allocation.
FreeRTOS documentation provides implementation of the following heap_1.c to heap_5.c implementations of malloc and free.