Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/*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;
}