ReAlloc for FreeRTOS

sarpdaltaban wrote on Friday, September 13, 2019:

Hello All,

Especially for dynamic memory allocation within UART callback, does anyone have an idea how to implement Re alloc function for RTOS? (Like PvPortRealloc(.,.))

It is because, let’s say I want to increment the allocation for a buffer each and every time one byte received by UART.

i.e.

//global variables
uint32_t bufferSize = 1;
uint8_t *rxBuffer = pvPortMalloc (bufferSize);
uint8_t incomingByte; 

//trigger UART callback when 1 byte is received
HAL_UART_Receive_IT(&huart3, &incomingByte, 1);

//UART callback function, enters per byte received
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == UART3)
	{
		rxBuffer[bufferSize - 1] = incomingByte;
        bufferSize++;
        rxBuffer = pvPortReAlloc (bufferSize);//we need this function :)
        
        HAL_UART_Receive_IT(&huart3, &incomingByte, 1);//trig again
	}
} 

Note: To use freeRTOS heap effectively, freeRTOS pvPortM… functions are supposed to be used instead of malloc, realloc and calloc functions. Otherwise, system heap will be used where freeRTOS memory will be partially useless.

Let me have your kind response at your earliest convenience.

Note: There are some pvPortRealloc functions on the web, github etc. However, they are creating new spaces before freeing the older ones, that makes duplicate memory usage…

richard_damon wrote on Friday, September 13, 2019:

If your environment is using newlib, with the multi-threaded option compiled in, then defining the malloc_lock and malloc_unlock functions is the best, at which point malloc/free/realloc/etc are now all thread safe and can be directly used.

The next option would be to extend heap3.c to include a wrapped version of realloc.

You could also rewrite heap4 or heap5 to include a realloc version, the simplest will just always create the new block as you saw, a smarter version would check of the block is followed by some free space and use it (which is basically what the library realloc does).

debugasm wrote on Monday, September 16, 2019:

Hi,

I have rewrite this:

// ******************************************************************************************************
// *                                                                                                    *
// * pvPortRealloc                                                                 						*
// *                                                                                                    *
// * Funzione per riallocare dimensione memoria in heap region											*
// *                                                                                                    *
// * Parameter : (void *) Pointer to a memory block previously allocated with malloc, calloc or realloc *
// *			 (size_t) Number of byte to resize section                                              *
// *                                                                                                    *
// * Return    : (void *) Pointer to allocate region, NULL if error on allocation                       *
// *                                                                                                    *
// ******************************************************************************************************

void *pvPortRealloc( void *pv, size_t xWantedSize )
{
	// Local variable	
	size_t move_size;
	size_t block_size;
	BlockLink_t *pxLink;
	void *pvReturn = NULL;
	uint8_t *puc = ( uint8_t * ) pv;

	// Se NULL, exit
	if (xWantedSize > 0)
	{
		// Controllo se buffer valido
		if (pv != NULL)
		{
			// The memory being freed will have an BlockLink_t structure immediately before it.
			puc -= xHeapStructSize;

			// This casting is to keep the compiler from issuing warnings.
			pxLink = ( void * ) puc;

			// Check allocate block
			if ((pxLink->xBlockSize & xBlockAllocatedBit) != 0)
			{
				// The block is being returned to the heap - it is no longer allocated.
				block_size = (pxLink->xBlockSize & ~xBlockAllocatedBit) - xHeapStructSize;

				// Alloco nuovo spazio di memoria
				pvReturn = pvPortCalloc(1, xWantedSize);

				// Check creation
				if (pvReturn != NULL)
				{
					// Sposta soltanto fino al limite
					if (block_size < xWantedSize)
					{
						// Il nuovo posto disponibile è inferiore
						move_size = block_size;
					}
					else
					{
						// Il nuovo posto disponibile è maggiore
						move_size = xWantedSize;
					}

					// Copio dati nel nuovo spazio di memoria
					memcpy(pvReturn, pv, move_size);

					// Libero vecchio blocco di memoria
					vPortFree(pv);
				}
			}
			else
			{
				// Puntatore nullo, alloca memoria come fosse nuova
				pvReturn = pvPortCalloc(1, xWantedSize);
			}
		}
		else
		{
			// Puntatore nullo, alloca memoria come fosse nuova
			pvReturn = pvPortCalloc(1, xWantedSize);
		}
	}
	else
	{
		// Exit without memory block
		pvReturn = NULL;
	}

	// Exit with memory block
	return pvReturn;
}