#include #include #include #include #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define portCHAR char #define portFLOAT float #define portDOUBLE double #define portLONG long #define portSHORT short #define portSTACK_TYPE uint32_t #define portBASE_TYPE long typedef portSTACK_TYPE StackType_t; typedef long BaseType_t; typedef unsigned long UBaseType_t; #define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configTOTAL_HEAP_SIZE 1024 #define configAPPLICATION_ALLOCATED_HEAP 0 #define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) // 8 #define pdFALSE ( ( BaseType_t ) 0 ) #define pdTRUE ( ( BaseType_t ) 1 ) #define portPOINTER_SIZE_TYPE uint32_t /* A few bytes might be lost to byte aligning the heap start address. */ #define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) /* * Initialises the heap structures before their first use. */ static void prvHeapInit(void); /* Allocate the memory for the heap. */ // #if( configAPPLICATION_ALLOCATED_HEAP == 1 ) // /* The application writer has already defined the array used for the RTOS // heap - probably so it can be placed in a special segment or address. */ // extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; // #else // static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; // #endif /* configAPPLICATION_ALLOCATED_HEAP */ static uint8_t *ucHeap; void initMemoryManager(void * managedMemory) { ucHeap = managedMemory; } /* Define the linked list structure. This is used to link free blocks in order of their size. */ typedef struct A_BLOCK_LINK { struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ size_t xBlockSize; /*<< The size of the free block. */ } BlockLink_t; static const uint16_t heapSTRUCT_SIZE = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); #define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) /* Create a couple of list links to mark the start and end of the list. */ static BlockLink_t xStart, xEnd; /* Keeps track of the number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE; /* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ /* * Insert a block into the list of free blocks - which is ordered by size of * the block. Small blocks at the start of the list and large blocks at the end * of the list. */ #define prvInsertBlockIntoFreeList( pxBlockToInsert ) \ { \ BlockLink_t *pxIterator; \ size_t xBlockSize; \ \ xBlockSize = pxBlockToInsert->xBlockSize; \ \ /* Iterate through the list until a block is found that has a larger size */ \ /* than the block we are inserting. */ \ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \ { \ /* There is nothing to do here - just iterate to the correct position. */ \ } \ \ /* Update the list to include the block being inserted in the correct */ \ /* position. */ \ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \ pxIterator->pxNextFreeBlock = pxBlockToInsert; \ } /*-----------------------------------------------------------*/ void *pvPortMalloc( size_t xWantedSize ) { BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; static BaseType_t xHeapHasBeenInitialised = pdFALSE; void *pvReturn = NULL; // vTaskSuspendAll(); { /* If this is the first call to malloc then the heap will require initialisation to setup the list of free blocks. */ if( xHeapHasBeenInitialised == pdFALSE ) { prvHeapInit(); xHeapHasBeenInitialised = pdTRUE; } /* The wanted size is increased so it can contain a BlockLink_t structure in addition to the requested amount of bytes. */ if( xWantedSize > 0 ) { xWantedSize += heapSTRUCT_SIZE; /* Ensure that blocks are always aligned to the required number of bytes. */ if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 ) { /* Byte alignment required. */ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } } if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) ) { /* Blocks are stored in byte order - traverse the list from the start (smallest) block until one of adequate size is found. */ pxPreviousBlock = &xStart; pxBlock = xStart.pxNextFreeBlock; while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) { pxPreviousBlock = pxBlock; pxBlock = pxBlock->pxNextFreeBlock; } /* If we found the end marker then a block of adequate size was not found. */ if( pxBlock != &xEnd ) { /* Return the memory space - jumping over the BlockLink_t structure at its start. */ pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); /* This block is being returned for use so must be taken out of the list of free blocks. */ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; /* If the block is larger than required it can be split into two. */ if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) { /* This block is to be split into two. Create a new block following the number of bytes requested. The void cast is used to prevent byte alignment warnings from the compiler. */ pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); /* Calculate the sizes of two blocks split from the single block. */ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; pxBlock->xBlockSize = xWantedSize; /* Insert the new block into the list of free blocks. */ prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); } xFreeBytesRemaining -= pxBlock->xBlockSize; } } // traceMALLOC( pvReturn, xWantedSize ); } // ( void ) xTaskResumeAll(); // #if( configUSE_MALLOC_FAILED_HOOK == 1 ) // { // if( pvReturn == NULL ) // { // extern void vApplicationMallocFailedHook( void ); // vApplicationMallocFailedHook(); // } // } // #endif return pvReturn; } /*-----------------------------------------------------------*/ void vPortFree( void *pv ) { uint8_t *puc = ( uint8_t * ) pv; BlockLink_t *pxLink; if( pv != NULL ) { /* The memory being freed will have an BlockLink_t structure immediately before it. */ puc -= heapSTRUCT_SIZE; /* This unexpected casting is to keep some compilers from issuing byte alignment warnings. */ pxLink = ( void * ) puc; // vTaskSuspendAll(); { /* Add this block to the list of free blocks. */ prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); xFreeBytesRemaining += pxLink->xBlockSize; // traceFREE( pv, pxLink->xBlockSize ); } // ( void ) xTaskResumeAll(); } } /*-----------------------------------------------------------*/ size_t xPortGetFreeHeapSize( void ) { return xFreeBytesRemaining; } /*-----------------------------------------------------------*/ void vPortInitialiseBlocks( void ) { /* This just exists to keep the linker quiet. */ } /*-----------------------------------------------------------*/ static void prvHeapInit( void ) { BlockLink_t *pxFirstFreeBlock; uint8_t *pucAlignedHeap; /* Ensure the heap starts on a correctly aligned boundary. */ pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /* xStart is used to hold a pointer to the first item in the list of free blocks. The void cast is used to prevent compiler warnings. */ xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; xStart.xBlockSize = ( size_t ) 0; /* xEnd is used to mark the end of the list of free blocks. */ xEnd.xBlockSize = configADJUSTED_HEAP_SIZE; xEnd.pxNextFreeBlock = NULL; /* To start with there is a single free block that is sized to take up the entire heap space. */ pxFirstFreeBlock = ( void * ) pucAlignedHeap; pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE; pxFirstFreeBlock->pxNextFreeBlock = &xEnd; } /*-----------------------------------------------------------*/ // #endif /* #ifdef configHEAP_ALLOCATION_SCHEME */ // #endif /* #if(configHEAP_ALLOCATION_SCHEME == HEAP_ALLOCATION_TYPE1) */ char testOne() { void * alloc1 = pvPortMalloc(100); void * alloc2 = pvPortMalloc(200); void * alloc3 = pvPortMalloc(300); memset(alloc1, 1, 100); memset(alloc2, 2, 200); memset(alloc3, 3, 300); for (int i = 0; i < 600; i++) { if (i < 100) { assert(*((char *) alloc1+i) == 1); } else if (i < 300) { assert(*((char *) alloc2+i-100) == 2); } else if (i < 600) { assert(*((char *) alloc3+i-300) == 3); } } return EXIT_SUCCESS; } static unsigned long int next = 1; int rand(void) // RAND_MAX assumed to be 32767 { next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768; } /* char testTwo() { void * ptr; while (ptr != NULL){ ptr = memMalloc((rand() % 2000) + 1); if (!((char *) memoryManager->nextAddress >= memoryManager->initialAddress)) { printStringLen(13, "allocRand1 -- ERROR", 31); new_line(); return EXIT_FAILURE; } if (!((char *) memoryManager->nextAddress <= memoryManager->initialAddress + MANAGED_MEMORY_SIZE)) { printStringLen(13, "allocRand2 -- ERROR", 31); new_line(); return EXIT_FAILURE; } // if (!((char *) memoryManager->lastAddress >= memoryManager->initialAddress)) { // } // if (!((char *) memoryManager->lastAddress <= memoryManager->initialAddress + MANAGED_MEMORY_SIZE)) { // } } return EXIT_SUCCESS; } */ // char mem[1024]; int main() { // initMemoryManager(mem); if (testOne() == EXIT_FAILURE) return EXIT_FAILURE; // if (testTwo() == EXIT_FAILURE) // return EXIT_FAILURE; }