int prvHeapAddMemBank(char *chunk_start, size_t size) { xBlockLink *pxIterator; xBlockLink *pxNewBlock; xBlockLink *pxAllocBlock; xBlockLink *p; /* Ensure that blocks are always aligned to the required number of bytes. */ DTRACE("AddMemBank: Received size: %u\r\n", size); /* Make sure chunk_start is on portBYTE_ALIGNMENT */ if( (unsigned long) chunk_start & portBYTE_ALIGNMENT_MASK ) { chunk_start += ( portBYTE_ALIGNMENT - ( (unsigned long) chunk_start & portBYTE_ALIGNMENT_MASK ) ); size -= ( portBYTE_ALIGNMENT - ( (unsigned long) chunk_start & portBYTE_ALIGNMENT_MASK ) ); } if( size & portBYTE_ALIGNMENT_MASK ) { /* Let go of the last few bytes */ size -= ( size & portBYTE_ALIGNMENT_MASK ) ; } DTRACE("AddMemBank: Fixed size: %u\r\n", size); vTaskSuspendAll(); /* Initialize heap if not already */ if( xHeapHasBeenInitialised == pdFALSE ) { prvHeapInit(); xHeapHasBeenInitialised = pdTRUE; } for( pxIterator = ( xBlockLink * )xHeap.ucHeap; NEXT_BLOCK(pxIterator) != (void *)lastHeapAddress; pxIterator = NEXT_BLOCK(pxIterator) ) { } if (!IS_FREE_BLOCK(pxIterator)) { /* For adding a new chunk it is important that the last part of the * previous chunk is empty (ie end of SRAM0 should be available) */ DTRACE("End of the first bank is not free. Cannot add new memory bank"); return pdFAIL; } if ((chunk_start - (char *)lastHeapAddress) < heapMINIMUM_BLOCK_SIZE) { /* Too small hole in between */ DTRACE("Too Small Hole in between %p %p %d\r\n", chunk_start, lastHeapAddress, heapMINIMUM_BLOCK_SIZE); return pdFAIL; } if (chunk_start < (char *)startHeapAddress) { DTRACE("Adding of a memory bank BEFORE the default heap is not supported"); return pdFAIL; } /* pxIterator should now point to the free block that contains the end * of the previous chunk. * We have to split this now, such that end of the previous chunk * contains the heapSTRUCT. This heapSTRUCT should say that the entire * hole from end of SRAM0 to start of the free space in SRAM1 is a huge * allocation. */ /* Fix the size of the last free block */ /* XXX Check if we are creating a block lesser than the minimum allowed * block size */ DTRACE("AddMemBank: Last Block: %p size %u\r\n", pxIterator, pxIterator->xBlockSize); pxIterator->xBlockSize -= heapSTRUCT_SIZE; unsigned unalignment = (pxIterator->xBlockSize & portBYTE_ALIGNMENT_MASK); if (unalignment) { pxIterator->xBlockSize -= unalignment; } DTRACE("AddMemBank: Fixed Last Block size %u\r\n", pxIterator->xBlockSize); /* Create a new block that marks the hole as allocated */ pxAllocBlock = NEXT_BLOCK(pxIterator); DTRACE("AddMemBank: Alloc Block: %p \r\n", pxAllocBlock); pxAllocBlock->xBlockSize = chunk_start - (char *)lastHeapAddress + heapSTRUCT_SIZE + unalignment; DTRACE("AddMemBank: Alloc Block: %p size %u\r\n", pxAllocBlock, pxAllocBlock->xBlockSize); /* These are never used for an allocated block*/ pxAllocBlock->pxNextFreeBlock = NULL; pxAllocBlock->pxPrev = pxIterator; SET_ALLOCATED(pxAllocBlock); /* Manage all accounting variables */ lastHeapAddress = (size_t)(chunk_start + size); xFreeBytesRemaining += size; configTOTAL_HEAP_SIZE += size; #ifdef FREERTOS_ENABLE_MALLOC_STATS hI.heapSize += size; #endif // FREERTOS_ENABLE_MALLOC_STATS xEnd.xBlockSize = configTOTAL_HEAP_SIZE; /* Create a new block at the start of the chunk_start */ /* Ensure the allocation flags aren't part of the block size */ pxNewBlock = NEXT_BLOCK(pxAllocBlock); DTRACE("AddMemBank: New Block: %p \r\n", pxNewBlock); pxNewBlock->xBlockSize = size; pxNewBlock->pxNextFreeBlock = &xEnd; pxNewBlock->pxPrev = pxAllocBlock; /* Iterate through the list until a block is found that has a larger size */ /* than the block we are inserting. */ for( p = &xStart; (p->pxNextFreeBlock != &xEnd) && (p->pxNextFreeBlock->xBlockSize < size); p = p->pxNextFreeBlock ) { /* There is nothing to do here - just iterate to the correct position. */ } if (p->pxNextFreeBlock == &xEnd) { /* Ours is the largest block */ p->pxNextFreeBlock = pxNewBlock; } else { /* Update the list to include the block being inserted in the correct */ /* position. */ pxNewBlock->pxNextFreeBlock = p->pxNextFreeBlock; p->pxNextFreeBlock = pxNewBlock; } DTRACE("AddMemBank: New Block: %p size %u\r\n", pxNewBlock, pxNewBlock->xBlockSize); xTaskResumeAll(); return pdPASS; }
void *pvPortMalloc( size_t xWantedSize ) { xBlockLink *pxBlock = NULL, *pxPreviousBlock, *pxNewBlockLink; void *pvReturn = NULL; if(!xWantedSize) return NULL; pre_alloc_hook( xWantedSize ); 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 xBlockLink 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 ) { /* Byte alignment required. */ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } } if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_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 ) ) { 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 xBlockLink structure at its start. */ pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); #ifdef FREERTOS_ENABLE_MALLOC_STATS hI.totalAllocations++; #endif // FREERTOS_ENABLE_MALLOC_STATS /* This block is being returned for use so must be taken off the list of free blocks. */ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; pxBlock->pxNextFreeBlock = NULL; /* 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 * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize ); /* Calculate the sizes of two blocks split from the single block. */ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; /* Assume bit 0 is 0 i.e. BLOCK_ALLOCATED flag is clear */ pxBlock->xBlockSize = xWantedSize; /* Add the new block to the serial list */ pxNewBlockLink->pxPrev = pxBlock; if( ! IS_LAST_BLOCK(pxNewBlockLink) ) NEXT_BLOCK( pxNewBlockLink )->pxPrev = pxNewBlockLink; SET_ALLOCATED(pxBlock); /* insert the new block into the list of free blocks. */ prvInsertBlockIntoFreeList( pxNewBlockLink ); } else { SET_ALLOCATED(pxBlock); } xFreeBytesRemaining -= BLOCK_SIZE(pxBlock); } } } xTaskResumeAll(); #if( configUSE_MALLOC_FAILED_HOOK == 1 ) { if( pvReturn == NULL ) { DTRACE("Heap allocation failed.\n\r" "Requested: %d\n\r" "Available : %d\n\r", xWantedSize, xFreeBytesRemaining); extern void vApplicationMallocFailedHook( void ); vApplicationMallocFailedHook(); } } #else if( pvReturn == NULL ) { DTRACE("Heap allocation failed.\n\r" "Requested: %d\n\r" "Available : %d\n\r", xWantedSize, xFreeBytesRemaining); #ifdef FREERTOS_ENABLE_MALLOC_STATS hI.failedAllocations++; #endif /* FREERTOS_ENABLE_MALLOC_STATS */ } #endif if(pvReturn) { SET_ACTUAL_SIZE( pxBlock ); SET_CALLER_ADDR( pxBlock ); ATRACE("MDC A %10x %6d %10d R: %x\r\n", pvReturn , BLOCK_SIZE( pxBlock ), xFreeBytesRemaining, __builtin_return_address(0)); randomizeAreaData((unsigned char*)pvReturn, BLOCK_SIZE( pxBlock ) - heapSTRUCT_SIZE); post_alloc_hook( pvReturn ); #ifdef FREERTOS_ENABLE_MALLOC_STATS if ((configTOTAL_HEAP_SIZE - xFreeBytesRemaining) > hI.peakHeapUsage) { hI.peakHeapUsage = (configTOTAL_HEAP_SIZE - xFreeBytesRemaining); } #endif } return pvReturn; }
/*attempts to allocate the requested number bytes, as a contigous chunk of memory, returns the pointer to the first byte on success * or returns NULL on failure*/ void* st_memmgr_alloc(uint16_t size){ MEMORY_DESCRIPTOR *mem_desc; uint8_t bank_visit_counter=0; uint16_t i; uint16_t cont_free_block_size; void* return_addr=NULL; size+=sizeof(MEMORY_DESCRIPTOR); //account for the memory descriptor if(size > BANK_1_SIZE) //if size is greater than the size of BANK_1 then allocation will fail goto RETURN_ALLOCATE; if(size<=MEM_REQUEST_SMALL) goto MEMORY_BANK_0; else goto MEMORY_BANK_1; MEMORY_BANK_0:; bank_visit_counter++; if(bank_visit_counter==MAX_ATTEMPTS) //all banks visited goto RETURN_ALLOCATE; i=0; cont_free_block_size=0; mem_desc=(MEMORY_DESCRIPTOR*)st_memory.BANK_0; //start of BANK_0 while(i<BANK_0_SIZE){ //search till the end of BANK_0 boundary if(IS_ALLOCATED((*mem_desc))){ //this bank is allocated i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); cont_free_block_size=0; continue; }else{ cont_free_block_size+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); if(cont_free_block_size >= size) break; //found a free block large enough to satisfy memory request i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); } } if(i>=BANK_0_SIZE) //failed to satisfy request in MEMORY_BANK_0 goto MEMORY_BANK_1; /*free block found, allocate whatever is required and make the rest space as a free block*/ if(calculateBlockOffset(size) < calculateBlockOffset(cont_free_block_size)){ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here /*make a new free block*/ mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); CLEAR_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc), (calculateBlockOffset(cont_free_block_size)-calculateBlockOffset(size))); }else{ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here } goto RETURN_ALLOCATE; MEMORY_BANK_1:; bank_visit_counter++; if(bank_visit_counter==MAX_ATTEMPTS) //all banks visited goto RETURN_ALLOCATE; i=0; cont_free_block_size=0; mem_desc=(MEMORY_DESCRIPTOR*)st_memory.BANK_1; //start of BANK_1 while(i<BANK_1_SIZE){ //search till the end of BANK_0 boundary if(IS_ALLOCATED((*mem_desc))){ //this bank is allocated i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); cont_free_block_size=0; continue; }else{ cont_free_block_size+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); if(cont_free_block_size >= size) break; //found a free block large enough to satisfy memory request i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); } } if(i>=BANK_1_SIZE) //failed to satisfy request in MEMORY_BANK_1 goto MEMORY_BANK_0; /*free block found, allocate whatever is required and make the rest space as a free block*/ if(calculateBlockOffset(size) < calculateBlockOffset(cont_free_block_size)){ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here /*make a new free block*/ mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); CLEAR_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc), (calculateBlockOffset(cont_free_block_size)-calculateBlockOffset(size))); }else{ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here } goto RETURN_ALLOCATE; RETURN_ALLOCATE:; lastRequestSize=size; if(return_addr!=NULL){ actual_memory_utilization+=size; lastRequestStatus=1; if(actual_memory_utilization>peak_memory_utilization) peak_memory_utilization=actual_memory_utilization; }else lastRequestStatus=0; return return_addr; }