00001 /* 00002 FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd. 00003 00004 *************************************************************************** 00005 * * 00006 * If you are: * 00007 * * 00008 * + New to FreeRTOS, * 00009 * + Wanting to learn FreeRTOS or multitasking in general quickly * 00010 * + Looking for basic training, * 00011 * + Wanting to improve your FreeRTOS skills and productivity * 00012 * * 00013 * then take a look at the FreeRTOS eBook * 00014 * * 00015 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * 00016 * http://www.FreeRTOS.org/Documentation * 00017 * * 00018 * A pdf reference manual is also available. Both are usually delivered * 00019 * to your inbox within 20 minutes to two hours when purchased between 8am * 00020 * and 8pm GMT (although please allow up to 24 hours in case of * 00021 * exceptional circumstances). Thank you for your support! * 00022 * * 00023 *************************************************************************** 00024 00025 This file is part of the FreeRTOS distribution. 00026 00027 FreeRTOS is free software; you can redistribute it and/or modify it under 00028 the terms of the GNU General Public License (version 2) as published by the 00029 Free Software Foundation AND MODIFIED BY the FreeRTOS exception. 00030 ***NOTE*** The exception to the GPL is included to allow you to distribute 00031 a combined work that includes FreeRTOS without being obliged to provide the 00032 source code for proprietary components outside of the FreeRTOS kernel. 00033 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT 00034 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00035 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00036 more details. You should have received a copy of the GNU General Public 00037 License and the FreeRTOS license exception along with FreeRTOS; if not it 00038 can be viewed here: http://www.freertos.org/a00114.html and also obtained 00039 by writing to Richard Barry, contact details for whom are available on the 00040 FreeRTOS WEB site. 00041 00042 1 tab == 4 spaces! 00043 00044 http://www.FreeRTOS.org - Documentation, latest information, license and 00045 contact details. 00046 00047 http://www.SafeRTOS.com - A version that is certified for use in safety 00048 critical systems. 00049 00050 http://www.OpenRTOS.com - Commercial support, development, porting, 00051 licensing and training services. 00052 */ 00053 00054 /* 00055 * A sample implementation of pvPortMalloc() and vPortFree() that permits 00056 * allocated blocks to be freed, but does not combine adjacent free blocks 00057 * into a single larger block. 00058 * 00059 * See heap_1.c and heap_3.c for alternative implementations, and the memory 00060 * management pages of http://www.FreeRTOS.org for more information. 00061 */ 00062 #include <stdlib.h> 00063 00064 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining 00065 all the API functions to use the MPU wrappers. That should only be done when 00066 task.h is included from an application file. */ 00067 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE 00068 00069 #include "FreeRTOS.h" 00070 #include "task.h" 00071 00072 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE 00073 00074 /* Allocate the memory for the heap. The struct is used to force byte 00075 alignment without using any non-portable code. */ 00076 static union xRTOS_HEAP 00077 { 00078 #if portBYTE_ALIGNMENT == 8 00079 volatile portDOUBLE dDummy; 00080 #else 00081 volatile unsigned long ulDummy; 00082 #endif 00083 unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]; 00084 } xHeap; 00085 00086 /* Define the linked list structure. This is used to link free blocks in order 00087 of their size. */ 00088 typedef struct A_BLOCK_LINK 00089 { 00090 struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ 00091 size_t xBlockSize; /*<< The size of the free block. */ 00092 } xBlockLink; 00093 00094 00095 static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) ); 00096 #define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) 00097 00098 /* Create a couple of list links to mark the start and end of the list. */ 00099 static xBlockLink xStart, xEnd; 00100 00101 /* Keeps track of the number of free bytes remaining, but says nothing about 00102 fragmentation. */ 00103 static size_t xFreeBytesRemaining; 00104 00105 /* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ 00106 00107 /* 00108 * Insert a block into the list of free blocks - which is ordered by size of 00109 * the block. Small blocks at the start of the list and large blocks at the end 00110 * of the list. 00111 */ 00112 #define prvInsertBlockIntoFreeList( pxBlockToInsert ) \ 00113 { \ 00114 xBlockLink *pxIterator; \ 00115 size_t xBlockSize; \ 00116 \ 00117 xBlockSize = pxBlockToInsert->xBlockSize; \ 00118 \ 00119 /* Iterate through the list until a block is found that has a larger size */ \ 00120 /* than the block we are inserting. */ \ 00121 for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \ 00122 { \ 00123 /* There is nothing to do here - just iterate to the correct position. */ \ 00124 } \ 00125 \ 00126 /* Update the list to include the block being inserted in the correct */ \ 00127 /* position. */ \ 00128 pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \ 00129 pxIterator->pxNextFreeBlock = pxBlockToInsert; \ 00130 } 00131 /*-----------------------------------------------------------*/ 00132 00133 #define prvHeapInit() \ 00134 { \ 00135 xBlockLink *pxFirstFreeBlock; \ 00136 \ 00137 /* xStart is used to hold a pointer to the first item in the list of free */ \ 00138 /* blocks. The void cast is used to prevent compiler warnings. */ \ 00139 xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap; \ 00140 xStart.xBlockSize = ( size_t ) 0; \ 00141 \ 00142 /* xEnd is used to mark the end of the list of free blocks. */ \ 00143 xEnd.xBlockSize = configTOTAL_HEAP_SIZE; \ 00144 xEnd.pxNextFreeBlock = NULL; \ 00145 \ 00146 /* To start with there is a single free block that is sized to take up the \ 00147 entire heap space. */ \ 00148 pxFirstFreeBlock = ( void * ) xHeap.ucHeap; \ 00149 pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE; \ 00150 pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \ 00151 \ 00152 xFreeBytesRemaining = configTOTAL_HEAP_SIZE; \ 00153 } 00154 /*-----------------------------------------------------------*/ 00155 00156 void *pvPortMalloc( size_t xWantedSize ) 00157 { 00158 xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink; 00159 static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE; 00160 void *pvReturn = NULL; 00161 00162 vTaskSuspendAll(); 00163 { 00164 /* If this is the first call to malloc then the heap will require 00165 initialisation to setup the list of free blocks. */ 00166 if( xHeapHasBeenInitialised == pdFALSE ) 00167 { 00168 prvHeapInit(); 00169 xHeapHasBeenInitialised = pdTRUE; 00170 } 00171 00172 /* The wanted size is increased so it can contain a xBlockLink 00173 structure in addition to the requested amount of bytes. */ 00174 if( xWantedSize > 0 ) 00175 { 00176 xWantedSize += heapSTRUCT_SIZE; 00177 00178 /* Ensure that blocks are always aligned to the required number of bytes. */ 00179 if( xWantedSize & portBYTE_ALIGNMENT_MASK ) 00180 { 00181 /* Byte alignment required. */ 00182 xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); 00183 } 00184 } 00185 00186 if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) ) 00187 { 00188 /* Blocks are stored in byte order - traverse the list from the start 00189 (smallest) block until one of adequate size is found. */ 00190 pxPreviousBlock = &xStart; 00191 pxBlock = xStart.pxNextFreeBlock; 00192 while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) ) 00193 { 00194 pxPreviousBlock = pxBlock; 00195 pxBlock = pxBlock->pxNextFreeBlock; 00196 } 00197 00198 /* If we found the end marker then a block of adequate size was not found. */ 00199 if( pxBlock != &xEnd ) 00200 { 00201 /* Return the memory space - jumping over the xBlockLink structure 00202 at its start. */ 00203 pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); 00204 00205 /* This block is being returned for use so must be taken our of the 00206 list of free blocks. */ 00207 pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; 00208 00209 /* If the block is larger than required it can be split into two. */ 00210 if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) 00211 { 00212 /* This block is to be split into two. Create a new block 00213 following the number of bytes requested. The void cast is 00214 used to prevent byte alignment warnings from the compiler. */ 00215 pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize ); 00216 00217 /* Calculate the sizes of two blocks split from the single 00218 block. */ 00219 pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; 00220 pxBlock->xBlockSize = xWantedSize; 00221 00222 /* Insert the new block into the list of free blocks. */ 00223 prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); 00224 } 00225 00226 xFreeBytesRemaining -= xWantedSize; 00227 } 00228 } 00229 } 00230 xTaskResumeAll(); 00231 00232 #if( configUSE_MALLOC_FAILED_HOOK == 1 ) 00233 { 00234 if( pvReturn == NULL ) 00235 { 00236 extern void vApplicationMallocFailedHook( void ); 00237 vApplicationMallocFailedHook(); 00238 } 00239 } 00240 #endif 00241 00242 return pvReturn; 00243 } 00244 /*-----------------------------------------------------------*/ 00245 00246 void vPortFree( void *pv ) 00247 { 00248 unsigned char *puc = ( unsigned char * ) pv; 00249 xBlockLink *pxLink; 00250 00251 if( pv ) 00252 { 00253 /* The memory being freed will have an xBlockLink structure immediately 00254 before it. */ 00255 puc -= heapSTRUCT_SIZE; 00256 00257 /* This casting is to keep the compiler from issuing warnings. */ 00258 pxLink = ( void * ) puc; 00259 00260 vTaskSuspendAll(); 00261 { 00262 /* Add this block to the list of free blocks. */ 00263 prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) ); 00264 xFreeBytesRemaining += pxLink->xBlockSize; 00265 } 00266 xTaskResumeAll(); 00267 } 00268 } 00269 /*-----------------------------------------------------------*/ 00270 00271 size_t xPortGetFreeHeapSize( void ) 00272 { 00273 return xFreeBytesRemaining; 00274 } 00275 /*-----------------------------------------------------------*/ 00276 00277 void vPortInitialiseBlocks( void ) 00278 { 00279 /* This just exists to keep the linker quiet. */ 00280 }