OS  v7.3.3
Documentation
Memory Management

Overview

The QuarkTS OS is designed to support the development of safe-critical embedded applications. Dynamic memory allocation is not permitted for kernel design, as it may result in out-of-storage run-time failures that are undesirable. However, some applications can be easily deployed using this allocation scheme, making a safe and portable implementation crucial for user code.

In a typical C environment, memory allocation can be achieved using standard library functions like malloc() and free(). However, they may not be appropriate for most embedded applications, as they may not be available on small microcontrollers or could consume a substantial amount of code space. Furthermore, dynamic memory allocation has several implementation-defined behaviors and potential issues such as fragmentation.

To address these concerns, the OS offers its own memory management interface for dynamic allocation as a fully kernel-independent extension. Instead of calling malloc() or free(), the application can use qMalloc() to allocate RAM, and qFree() to free it when necessary. These functions have the same prototypes as their standard C library counterparts.

Principle of operation

The allocation scheme works by subdividing a static array into smaller blocks and using the First-Fit approach.

memmang
First-fit allocation policy

If adjacent free blocks are available, the implementation combines them into a single larger block, minimizing the risk of fragmentation, making it suitable for applications that repeatedly allocate and free different sized blocks of RAM.

Note
Because memory is statically declared, it will make the application appear to consume a lot of RAM, even before any memory has been allocated from it.
Warning
All the memory management APIs are NOT interrupt-safe. Use these APIs only from the base context.
Attention
The application is not exempt from memory leaks if the user does not perform adequate memory management. Here, the worst-case scenario can occur in the absence of free memory.

Memory pools

A memory pool is a special resource that allows memory blocks to be dynamically allocated from a user-designated memory region. Instead of typical pools with fixed size block allocation, the pools in QuarkTS can be of any size, thereby the user is responsible for selecting the appropriate memory pool to allocate data with the same size.

The default memory management unit resides in a memory pool object. Also called the "default pool". The total amount of available heap space in the default memory pool is set by Q_DEFAULT_HEAP_SIZE, which is defined in qconfig.h.

Besides the default pool, any number of additional memory pools can be defined. Like any other object in QuarkTS, memory pools are referenced by handles, a variable of type qMemMang_Pool_t and should be initialized before use with the qMemMang_Pool_Setup() API function.

To perform operations in another memory pool, besides the default pool, an explicit switch should be performed using qMemMang_Pool_Select(). Here, a pointer to the target pool should be passed as input argument. From now on, every call to qMalloc(), or qFree() will run over the newly selected memory pool. To return to the default pool, a new call to qMemMang_Pool_Select() is required passing NULL as input argument.

To keep track of the memory usage, the qMemMang_Get_FreeSize() API function returns the number of free bytes in the memory pool at the time the function is called.

Usage example

#include <stdio.h>
#include <stdlib.h>
#include "QuarkTS.h"
#include "HAL.h"
#include "Core.h"
qTask_t taskA;
qMemMang_Pool_t another_heap;
void taskA_Callback( qEvent_t e );
void taskA_Callback( qEvent_t e ) {
int *xdata = NULL;
int *ydata = NULL;
int *xyoper = NULL;
int n = 20;
int i;
xyoper = (int*)qMalloc( n*sizeof(int) );
xdata = (int*)qMalloc( n*sizeof(int) );
qMemMang_Pool_Select( &another_heap ); /*change the memory pool*/
/*ydata will point to a segment allocated in another pool*/
ydata = (int*)qMalloc( n*sizeof(int) );
/*use the memory if could be allocated*/
if ( xdata && ydata && xyoper ) {
for ( i = 0 ; i < n ; i++ ) {
xdata[ i ] = GetXData();
ydata[ i ] = GetYData();
xyoper[ i ] = xdata[ i ]*ydata[ i ];
}
UseTheMemmory(xyoper);
}
else {
qTrace_Message("ERROR:ALLOCATION_FAIL");
}
qFree( ydata );
qMemMang_Pool_Select( NULL ); /*return to the default pool*/
qFree( xdata );
qFree( xyoper );
}
int main(void) {
char area_another_heap[ 512 ] = { 0 };
qTrace_Set_OutputFcn( OutPutChar );
/*Create a memory heap*/
qMemMang_Pool_Setup( &another_heap, area_another_heap, 512 );
qOS_Setup( HAL_GetTick, 0.001f, IdleTaskCallback );
qOS_Add_Task( &taskA, taskA_Callback, qLowest_Priority, 0.1f, qPeriodic, qEnabled, NULL );
return 0;
}
void qFree(void *ptr)
Wrapper API for qMemMang_Free() in order to be compatible with free(). Deallocates the space previous...
void * qMalloc(size_t mSize)
Wrapper API for qMemMang_Allocate() in order to be compatible with malloc(). Allocate a block of memo...
qBool_t qMemMang_Pool_Select(qMemMang_Pool_t *const mPool)
Select the memory pool to perform heap memory requests with qMalloc() and qFree().
qBool_t qMemMang_Pool_Setup(qMemMang_Pool_t *const mPool, void *pArea, const size_t pSize)
Initializes a memory pool instance. This function should be called once before any heap memory reques...
qBool_t qOS_Add_Task(qTask_t *const Task, qTaskFcn_t callbackFcn, const qPriority_t p, const qTime_t t, const qIteration_t n, const qState_t init, void *arg)
Add a task to the scheduling scheme. The task is scheduled to run every t seconds,...
Definition: qkernel.c:411
#define qLowest_Priority
A macro directive to indicate the lowest priority level.
Definition: qkernel.h:71
qBool_t qOS_Run(void)
Executes the scheduling scheme. It must be called once after the task pool has been defined.
Definition: qkernel.c:676
qBool_t qOS_Setup(const qGetTickFcn_t tFcn, const qTimingBase_t t, qTaskFcn_t idleCallback)
Task Scheduler Setup. This function is required and must be called once in the application main threa...
Definition: qkernel.c:126
#define qPeriodic
A directive indicating that the task will run every time its timeout has expired.
Definition: qkernel.h:80
void qTrace_Set_OutputFcn(qPutChar_t fcn)
This API set the output method for debug/trace messages.
#define qEnabled
A state value that enables a task.
Definition: qtypes.h:167
The task argument with all the regarding information of the task execution.
Definition: qtasks.h:162
A Memory Pool object.
Definition: qmemmang.h:74
A task node object.
Definition: qtasks.h:268