Imported upstream version 1.20
[fw/openalt] / FreeRTOS / portable / MemMang / heap_2.c
1 /*
2         FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
3
4         This file is part of the FreeRTOS.org distribution.
5
6         FreeRTOS.org is free software; you can redistribute it and/or modify
7         it under the terms of the GNU General Public License as published by
8         the Free Software Foundation; either version 2 of the License, or
9         (at your option) any later version.
10
11         FreeRTOS.org is distributed in the hope that it will be useful,
12         but WITHOUT ANY WARRANTY; without even the implied warranty of
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14         GNU General Public License for more details.
15
16         You should have received a copy of the GNU General Public License
17         along with FreeRTOS.org; if not, write to the Free Software
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20         A special exception to the GPL can be applied should you wish to distribute
21         a combined work that includes FreeRTOS.org, without being obliged to provide
22         the source code for any proprietary components.  See the licensing section
23         of http://www.FreeRTOS.org for full details of how and when the exception
24         can be applied.
25
26         ***************************************************************************
27         See http://www.FreeRTOS.org for documentation, latest information, license
28         and contact details.  Please ensure to read the configuration and relevant
29         port sections of the online documentation.
30
31         Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
32         with commercial development and support options.
33         ***************************************************************************
34 */
35
36 /*
37  * A sample implementation of pvPortMalloc() and vPortFree() that permits
38  * allocated blocks to be freed, but does not combine adjacent free blocks
39  * into a single larger block.
40  *
41  * See heap_1.c and heap_3.c for alternative implementations, and the memory
42  * management pages of http://www.FreeRTOS.org for more information.
43  */
44 #include <stdlib.h>
45
46 #include "FreeRTOS.h"
47 #include "task.h"
48
49 /* Setup the correct byte alignment mask for the defined byte alignment. */
50
51 #if portBYTE_ALIGNMENT == 8
52         #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0007 )
53 #endif
54
55 #if portBYTE_ALIGNMENT == 4
56         #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0003 )
57 #endif
58
59 #if portBYTE_ALIGNMENT == 2
60         #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0001 )
61 #endif
62
63 #if portBYTE_ALIGNMENT == 1
64         #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0000 )
65 #endif
66
67 #ifndef heapBYTE_ALIGNMENT_MASK
68         #error "Invalid portBYTE_ALIGNMENT definition"
69 #endif
70
71 /* Allocate the memory for the heap.  The struct is used to force byte
72 alignment without using any non-portable code. */
73 static struct xRTOS_HEAP
74 {
75         unsigned portLONG ulDummy;
76         unsigned portCHAR ucHeap[ configTOTAL_HEAP_SIZE ];
77 } xHeap;
78
79 /* Define the linked list structure.  This is used to link free blocks in order
80 of their size. */
81 typedef struct A_BLOCK_LINK
82 {
83         struct A_BLOCK_LINK *pxNextFreeBlock;   /*<< The next free block in the list. */
84         size_t xBlockSize;                                              /*<< The size of the free block. */
85 } xBlockLink;
86
87
88 static const unsigned portSHORT  heapSTRUCT_SIZE        = ( sizeof( xBlockLink ) + ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
89 #define heapMINIMUM_BLOCK_SIZE  ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
90
91 /* Create a couple of list links to mark the start and end of the list. */
92 static xBlockLink xStart, xEnd;
93
94 /* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
95
96 /*
97  * Insert a block into the list of free blocks - which is ordered by size of
98  * the block.  Small blocks at the start of the list and large blocks at the end
99  * of the list.
100  */
101 #define prvInsertBlockIntoFreeList( pxBlockToInsert )                                                           \
102 {                                                                                                                                                                       \
103 xBlockLink *pxIterator;                                                                                                                         \
104 size_t xBlockSize;                                                                                                                                      \
105                                                                                                                                                                         \
106         xBlockSize = pxBlockToInsert->xBlockSize;                                                                               \
107                                                                                                                                                                         \
108         /* Iterate through the list until a block is found that has a larger size */    \
109         /* than the block we are inserting. */                                                                                  \
110         for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock )     \
111         {                                                                                                                                                               \
112                 /* There is nothing to do here - just iterate to the correct position. */       \
113         }                                                                                                                                                               \
114                                                                                                                                                                         \
115         /* Update the list to include the block being inserted in the correct */                \
116         /* position. */                                                                                                                                 \
117         pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;                                 \
118         pxIterator->pxNextFreeBlock = pxBlockToInsert;                                                                  \
119 }
120 /*-----------------------------------------------------------*/
121
122 #define prvHeapInit()                                                                                                                           \
123 {                                                                                                                                                                       \
124 xBlockLink *pxFirstFreeBlock;                                                                                                           \
125                                                                                                                                                                         \
126         /* xStart is used to hold a pointer to the first item in the list of free */    \
127         /* blocks.  The void cast is used to prevent compiler warnings. */                              \
128         xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap;                                                               \
129         xStart.xBlockSize = ( size_t ) 0;                                                                                               \
130                                                                                                                                                                         \
131         /* xEnd is used to mark the end of the list of free blocks. */                                  \
132         xEnd.xBlockSize = configTOTAL_HEAP_SIZE;                                                                                \
133         xEnd.pxNextFreeBlock = NULL;                                                                                                    \
134                                                                                                                                                                         \
135         /* To start with there is a single free block that is sized to take up the              \
136         entire heap space. */                                                                                                                   \
137         pxFirstFreeBlock = ( void * ) xHeap.ucHeap;                                                                             \
138         pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE;                                                   \
139         pxFirstFreeBlock->pxNextFreeBlock = &xEnd;                                                                              \
140 }
141 /*-----------------------------------------------------------*/
142
143 #if ( INCLUDE_vPortUsedMem == 1 )
144
145 void vPortUsedMem(int *bytesFree, int *bytesUsed, int *blocksFree)  
146 {  
147   xBlockLink *pxBlock = &xStart;  
148
149   *bytesFree = 0;  
150   *bytesUsed = 0;  
151   *blocksFree = 0;
152
153   vTaskSuspendAll();  
154
155   while ((pxBlock) && (pxBlock != &xEnd))  
156   {  
157     *bytesFree += pxBlock->xBlockSize;  
158     pxBlock = pxBlock->pxNextFreeBlock;  
159     ++*blocksFree;
160   }  
161
162   xTaskResumeAll();  
163
164   *bytesUsed = configTOTAL_HEAP_SIZE - *bytesFree;
165 }  
166
167 #endif
168 /*-----------------------------------------------------------*/
169
170 void *pvPortMalloc( size_t xWantedSize )
171 {
172   xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
173   static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
174   void *pvReturn = NULL;
175
176   vTaskSuspendAll();
177   {
178     /* If this is the first call to malloc then the heap will require
179        initialisation to setup the list of free blocks. */
180     if( xHeapHasBeenInitialised == pdFALSE )
181     {
182       prvHeapInit();
183       xHeapHasBeenInitialised = pdTRUE;
184     }
185
186     /* The wanted size is increased so it can contain a xBlockLink
187        structure in addition to the requested amount of bytes. */
188     if( xWantedSize > 0 )
189     {
190       xWantedSize += heapSTRUCT_SIZE;
191
192       /* Ensure that blocks are always aligned to the required number of bytes. */
193       if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
194       {
195         /* Byte alignment required. */
196         xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
197       }
198     }
199
200     if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )
201     {
202       /* Blocks are stored in byte order - traverse the list from the start
203          (smallest) block until one of adequate size is found. */
204       pxPreviousBlock = &xStart;
205       pxBlock = xStart.pxNextFreeBlock;
206       while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
207       {
208         pxPreviousBlock = pxBlock;
209         pxBlock = pxBlock->pxNextFreeBlock;
210       }
211
212       /* If we found the end marker then a block of adequate size was not found. */
213       if( pxBlock != &xEnd )
214       {
215         /* Return the memory space - jumping over the xBlockLink structure
216            at its start. */
217         pvReturn = ( void * ) ( ( ( unsigned portCHAR * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
218
219         /* This block is being returned for use so must be taken our of the
220            list of free blocks. */
221         pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
222
223         /* If the block is larger than required it can be split into two. */
224         if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
225         {
226           /* This block is to be split into two.  Create a new block
227              following the number of bytes requested. The void cast is
228              used to prevent byte alignment warnings from the compiler. */
229           pxNewBlockLink = ( void * ) ( ( ( unsigned portCHAR * ) pxBlock ) + xWantedSize );
230
231           /* Calculate the sizes of two blocks split from the single
232              block. */
233           pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;       
234           pxBlock->xBlockSize = xWantedSize;                    
235
236           /* Insert the new block into the list of free blocks. */
237           prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
238         }
239       }
240     }
241   }
242   xTaskResumeAll();
243
244   return pvReturn;
245 }
246 /*-----------------------------------------------------------*/
247
248 void vPortFree( void *pv )
249 {
250 unsigned portCHAR *puc = ( unsigned portCHAR * ) pv;
251 xBlockLink *pxLink;
252
253         if( pv )
254         {
255                 /* The memory being freed will have an xBlockLink structure immediately
256                 before it. */
257                 puc -= heapSTRUCT_SIZE;
258
259                 /* This casting is to keep the compiler from issuing warnings. */
260                 pxLink = ( void * ) puc;
261
262                 vTaskSuspendAll();
263                 {                               
264                         /* Add this block to the list of free blocks. */
265                         prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );
266                 }
267                 xTaskResumeAll();
268         }
269 }
270 /*-----------------------------------------------------------*/
271