]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/MemMang/heap_5.c
Continued to work on the MQTT demo project.
[freertos] / FreeRTOS / Source / portable / MemMang / heap_5.c
1 /*\r
2  * FreeRTOS Kernel V10.2.1\r
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /*\r
29  * A sample implementation of pvPortMalloc() that allows the heap to be defined\r
30  * across multiple non-contigous blocks and combines (coalescences) adjacent\r
31  * memory blocks as they are freed.\r
32  *\r
33  * See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative\r
34  * implementations, and the memory management pages of http://www.FreeRTOS.org\r
35  * for more information.\r
36  *\r
37  * Usage notes:\r
38  *\r
39  * vPortDefineHeapRegions() ***must*** be called before pvPortMalloc().\r
40  * pvPortMalloc() will be called if any task objects (tasks, queues, event\r
41  * groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be\r
42  * called before any other objects are defined.\r
43  *\r
44  * vPortDefineHeapRegions() takes a single parameter.  The parameter is an array\r
45  * of HeapRegion_t structures.  HeapRegion_t is defined in portable.h as\r
46  *\r
47  * typedef struct HeapRegion\r
48  * {\r
49  *      uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap.\r
50  *      size_t xSizeInBytes;      << Size of the block of memory.\r
51  * } HeapRegion_t;\r
52  *\r
53  * The array is terminated using a NULL zero sized region definition, and the\r
54  * memory regions defined in the array ***must*** appear in address order from\r
55  * low address to high address.  So the following is a valid example of how\r
56  * to use the function.\r
57  *\r
58  * HeapRegion_t xHeapRegions[] =\r
59  * {\r
60  *      { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000\r
61  *      { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000\r
62  *      { NULL, 0 }                << Terminates the array.\r
63  * };\r
64  *\r
65  * vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().\r
66  *\r
67  * Note 0x80000000 is the lower address so appears in the array first.\r
68  *\r
69  */\r
70 #include <stdlib.h>\r
71 \r
72 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
73 all the API functions to use the MPU wrappers.  That should only be done when\r
74 task.h is included from an application file. */\r
75 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
76 \r
77 #include "FreeRTOS.h"\r
78 #include "task.h"\r
79 \r
80 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
81 \r
82 #if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )\r
83         #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0\r
84 #endif\r
85 \r
86 /* Block sizes must not get too small. */\r
87 #define heapMINIMUM_BLOCK_SIZE  ( ( size_t ) ( xHeapStructSize << 1 ) )\r
88 \r
89 /* Assumes 8bit bytes! */\r
90 #define heapBITS_PER_BYTE               ( ( size_t ) 8 )\r
91 \r
92 /* Define the linked list structure.  This is used to link free blocks in order\r
93 of their memory address. */\r
94 typedef struct A_BLOCK_LINK\r
95 {\r
96         struct A_BLOCK_LINK *pxNextFreeBlock;   /*<< The next free block in the list. */\r
97         size_t xBlockSize;                                              /*<< The size of the free block. */\r
98 } BlockLink_t;\r
99 \r
100 /*-----------------------------------------------------------*/\r
101 \r
102 /*\r
103  * Inserts a block of memory that is being freed into the correct position in\r
104  * the list of free memory blocks.  The block being freed will be merged with\r
105  * the block in front it and/or the block behind it if the memory blocks are\r
106  * adjacent to each other.\r
107  */\r
108 static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );\r
109 \r
110 /*-----------------------------------------------------------*/\r
111 \r
112 /* The size of the structure placed at the beginning of each allocated memory\r
113 block must by correctly byte aligned. */\r
114 static const size_t xHeapStructSize     = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );\r
115 \r
116 /* Create a couple of list links to mark the start and end of the list. */\r
117 static BlockLink_t xStart, *pxEnd = NULL;\r
118 \r
119 /* Keeps track of the number of calls to allocate and free memory as well as the\r
120 number of free bytes remaining, but says nothing about fragmentation. */\r
121 static size_t xFreeBytesRemaining = 0U;\r
122 static size_t xMinimumEverFreeBytesRemaining = 0U;\r
123 static size_t xNumberOfSuccessfulAllocations = 0;\r
124 static size_t xNumberOfSuccessfulFrees = 0;\r
125 \r
126 /* Gets set to the top bit of an size_t type.  When this bit in the xBlockSize\r
127 member of an BlockLink_t structure is set then the block belongs to the\r
128 application.  When the bit is free the block is still part of the free heap\r
129 space. */\r
130 static size_t xBlockAllocatedBit = 0;\r
131 \r
132 /*-----------------------------------------------------------*/\r
133 \r
134 void *pvPortMalloc( size_t xWantedSize )\r
135 {\r
136 BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;\r
137 void *pvReturn = NULL;\r
138 \r
139         /* The heap must be initialised before the first call to\r
140         prvPortMalloc(). */\r
141         configASSERT( pxEnd );\r
142 \r
143         vTaskSuspendAll();\r
144         {\r
145                 /* Check the requested block size is not so large that the top bit is\r
146                 set.  The top bit of the block size member of the BlockLink_t structure\r
147                 is used to determine who owns the block - the application or the\r
148                 kernel, so it must be free. */\r
149                 if( ( xWantedSize & xBlockAllocatedBit ) == 0 )\r
150                 {\r
151                         /* The wanted size is increased so it can contain a BlockLink_t\r
152                         structure in addition to the requested amount of bytes. */\r
153                         if( xWantedSize > 0 )\r
154                         {\r
155                                 xWantedSize += xHeapStructSize;\r
156 \r
157                                 /* Ensure that blocks are always aligned to the required number\r
158                                 of bytes. */\r
159                                 if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )\r
160                                 {\r
161                                         /* Byte alignment required. */\r
162                                         xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );\r
163                                 }\r
164                                 else\r
165                                 {\r
166                                         mtCOVERAGE_TEST_MARKER();\r
167                                 }\r
168                         }\r
169                         else\r
170                         {\r
171                                 mtCOVERAGE_TEST_MARKER();\r
172                         }\r
173 \r
174                         if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )\r
175                         {\r
176                                 /* Traverse the list from the start     (lowest address) block until\r
177                                 one     of adequate size is found. */\r
178                                 pxPreviousBlock = &xStart;\r
179                                 pxBlock = xStart.pxNextFreeBlock;\r
180                                 while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )\r
181                                 {\r
182                                         pxPreviousBlock = pxBlock;\r
183                                         pxBlock = pxBlock->pxNextFreeBlock;\r
184                                 }\r
185 \r
186                                 /* If the end marker was reached then a block of adequate size\r
187                                 was     not found. */\r
188                                 if( pxBlock != pxEnd )\r
189                                 {\r
190                                         /* Return the memory space pointed to - jumping over the\r
191                                         BlockLink_t structure at its start. */\r
192                                         pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );\r
193 \r
194                                         /* This block is being returned for use so must be taken out\r
195                                         of the list of free blocks. */\r
196                                         pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
197 \r
198                                         /* If the block is larger than required it can be split into\r
199                                         two. */\r
200                                         if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )\r
201                                         {\r
202                                                 /* This block is to be split into two.  Create a new\r
203                                                 block following the number of bytes requested. The void\r
204                                                 cast is used to prevent byte alignment warnings from the\r
205                                                 compiler. */\r
206                                                 pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );\r
207 \r
208                                                 /* Calculate the sizes of two blocks split from the\r
209                                                 single block. */\r
210                                                 pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
211                                                 pxBlock->xBlockSize = xWantedSize;\r
212 \r
213                                                 /* Insert the new block into the list of free blocks. */\r
214                                                 prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );\r
215                                         }\r
216                                         else\r
217                                         {\r
218                                                 mtCOVERAGE_TEST_MARKER();\r
219                                         }\r
220 \r
221                                         xFreeBytesRemaining -= pxBlock->xBlockSize;\r
222 \r
223                                         if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )\r
224                                         {\r
225                                                 xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;\r
226                                         }\r
227                                         else\r
228                                         {\r
229                                                 mtCOVERAGE_TEST_MARKER();\r
230                                         }\r
231 \r
232                                         /* The block is being returned - it is allocated and owned\r
233                                         by the application and has no "next" block. */\r
234                                         pxBlock->xBlockSize |= xBlockAllocatedBit;\r
235                                         pxBlock->pxNextFreeBlock = NULL;\r
236                                         xNumberOfSuccessfulAllocations++;\r
237                                 }\r
238                                 else\r
239                                 {\r
240                                         mtCOVERAGE_TEST_MARKER();\r
241                                 }\r
242                         }\r
243                         else\r
244                         {\r
245                                 mtCOVERAGE_TEST_MARKER();\r
246                         }\r
247                 }\r
248                 else\r
249                 {\r
250                         mtCOVERAGE_TEST_MARKER();\r
251                 }\r
252 \r
253                 traceMALLOC( pvReturn, xWantedSize );\r
254         }\r
255         ( void ) xTaskResumeAll();\r
256 \r
257         #if( configUSE_MALLOC_FAILED_HOOK == 1 )\r
258         {\r
259                 if( pvReturn == NULL )\r
260                 {\r
261                         extern void vApplicationMallocFailedHook( void );\r
262                         vApplicationMallocFailedHook();\r
263                 }\r
264                 else\r
265                 {\r
266                         mtCOVERAGE_TEST_MARKER();\r
267                 }\r
268         }\r
269         #endif\r
270 \r
271         return pvReturn;\r
272 }\r
273 /*-----------------------------------------------------------*/\r
274 \r
275 void vPortFree( void *pv )\r
276 {\r
277 uint8_t *puc = ( uint8_t * ) pv;\r
278 BlockLink_t *pxLink;\r
279 \r
280         if( pv != NULL )\r
281         {\r
282                 /* The memory being freed will have an BlockLink_t structure immediately\r
283                 before it. */\r
284                 puc -= xHeapStructSize;\r
285 \r
286                 /* This casting is to keep the compiler from issuing warnings. */\r
287                 pxLink = ( void * ) puc;\r
288 \r
289                 /* Check the block is actually allocated. */\r
290                 configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );\r
291                 configASSERT( pxLink->pxNextFreeBlock == NULL );\r
292 \r
293                 if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )\r
294                 {\r
295                         if( pxLink->pxNextFreeBlock == NULL )\r
296                         {\r
297                                 /* The block is being returned to the heap - it is no longer\r
298                                 allocated. */\r
299                                 pxLink->xBlockSize &= ~xBlockAllocatedBit;\r
300 \r
301                                 vTaskSuspendAll();\r
302                                 {\r
303                                         /* Add this block to the list of free blocks. */\r
304                                         xFreeBytesRemaining += pxLink->xBlockSize;\r
305                                         traceFREE( pv, pxLink->xBlockSize );\r
306                                         prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );\r
307                                         xNumberOfSuccessfulFrees++;\r
308                                 }\r
309                                 ( void ) xTaskResumeAll();\r
310                         }\r
311                         else\r
312                         {\r
313                                 mtCOVERAGE_TEST_MARKER();\r
314                         }\r
315                 }\r
316                 else\r
317                 {\r
318                         mtCOVERAGE_TEST_MARKER();\r
319                 }\r
320         }\r
321 }\r
322 /*-----------------------------------------------------------*/\r
323 \r
324 size_t xPortGetFreeHeapSize( void )\r
325 {\r
326         return xFreeBytesRemaining;\r
327 }\r
328 /*-----------------------------------------------------------*/\r
329 \r
330 size_t xPortGetMinimumEverFreeHeapSize( void )\r
331 {\r
332         return xMinimumEverFreeBytesRemaining;\r
333 }\r
334 /*-----------------------------------------------------------*/\r
335 \r
336 static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )\r
337 {\r
338 BlockLink_t *pxIterator;\r
339 uint8_t *puc;\r
340 \r
341         /* Iterate through the list until a block is found that has a higher address\r
342         than the block being inserted. */\r
343         for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )\r
344         {\r
345                 /* Nothing to do here, just iterate to the right position. */\r
346         }\r
347 \r
348         /* Do the block being inserted, and the block it is being inserted after\r
349         make a contiguous block of memory? */\r
350         puc = ( uint8_t * ) pxIterator;\r
351         if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )\r
352         {\r
353                 pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;\r
354                 pxBlockToInsert = pxIterator;\r
355         }\r
356         else\r
357         {\r
358                 mtCOVERAGE_TEST_MARKER();\r
359         }\r
360 \r
361         /* Do the block being inserted, and the block it is being inserted before\r
362         make a contiguous block of memory? */\r
363         puc = ( uint8_t * ) pxBlockToInsert;\r
364         if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )\r
365         {\r
366                 if( pxIterator->pxNextFreeBlock != pxEnd )\r
367                 {\r
368                         /* Form one big block from the two blocks. */\r
369                         pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;\r
370                         pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;\r
371                 }\r
372                 else\r
373                 {\r
374                         pxBlockToInsert->pxNextFreeBlock = pxEnd;\r
375                 }\r
376         }\r
377         else\r
378         {\r
379                 pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;\r
380         }\r
381 \r
382         /* If the block being inserted plugged a gab, so was merged with the block\r
383         before and the block after, then it's pxNextFreeBlock pointer will have\r
384         already been set, and should not be set here as that would make it point\r
385         to itself. */\r
386         if( pxIterator != pxBlockToInsert )\r
387         {\r
388                 pxIterator->pxNextFreeBlock = pxBlockToInsert;\r
389         }\r
390         else\r
391         {\r
392                 mtCOVERAGE_TEST_MARKER();\r
393         }\r
394 }\r
395 /*-----------------------------------------------------------*/\r
396 \r
397 void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )\r
398 {\r
399 BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock;\r
400 size_t xAlignedHeap;\r
401 size_t xTotalRegionSize, xTotalHeapSize = 0;\r
402 BaseType_t xDefinedRegions = 0;\r
403 size_t xAddress;\r
404 const HeapRegion_t *pxHeapRegion;\r
405 \r
406         /* Can only call once! */\r
407         configASSERT( pxEnd == NULL );\r
408 \r
409         pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );\r
410 \r
411         while( pxHeapRegion->xSizeInBytes > 0 )\r
412         {\r
413                 xTotalRegionSize = pxHeapRegion->xSizeInBytes;\r
414 \r
415                 /* Ensure the heap region starts on a correctly aligned boundary. */\r
416                 xAddress = ( size_t ) pxHeapRegion->pucStartAddress;\r
417                 if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )\r
418                 {\r
419                         xAddress += ( portBYTE_ALIGNMENT - 1 );\r
420                         xAddress &= ~portBYTE_ALIGNMENT_MASK;\r
421 \r
422                         /* Adjust the size for the bytes lost to alignment. */\r
423                         xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;\r
424                 }\r
425 \r
426                 xAlignedHeap = xAddress;\r
427 \r
428                 /* Set xStart if it has not already been set. */\r
429                 if( xDefinedRegions == 0 )\r
430                 {\r
431                         /* xStart is used to hold a pointer to the first item in the list of\r
432                         free blocks.  The void cast is used to prevent compiler warnings. */\r
433                         xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;\r
434                         xStart.xBlockSize = ( size_t ) 0;\r
435                 }\r
436                 else\r
437                 {\r
438                         /* Should only get here if one region has already been added to the\r
439                         heap. */\r
440                         configASSERT( pxEnd != NULL );\r
441 \r
442                         /* Check blocks are passed in with increasing start addresses. */\r
443                         configASSERT( xAddress > ( size_t ) pxEnd );\r
444                 }\r
445 \r
446                 /* Remember the location of the end marker in the previous region, if\r
447                 any. */\r
448                 pxPreviousFreeBlock = pxEnd;\r
449 \r
450                 /* pxEnd is used to mark the end of the list of free blocks and is\r
451                 inserted at the end of the region space. */\r
452                 xAddress = xAlignedHeap + xTotalRegionSize;\r
453                 xAddress -= xHeapStructSize;\r
454                 xAddress &= ~portBYTE_ALIGNMENT_MASK;\r
455                 pxEnd = ( BlockLink_t * ) xAddress;\r
456                 pxEnd->xBlockSize = 0;\r
457                 pxEnd->pxNextFreeBlock = NULL;\r
458 \r
459                 /* To start with there is a single free block in this region that is\r
460                 sized to take up the entire heap region minus the space taken by the\r
461                 free block structure. */\r
462                 pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;\r
463                 pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;\r
464                 pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;\r
465 \r
466                 /* If this is not the first region that makes up the entire heap space\r
467                 then link the previous region to this region. */\r
468                 if( pxPreviousFreeBlock != NULL )\r
469                 {\r
470                         pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;\r
471                 }\r
472 \r
473                 xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;\r
474 \r
475                 /* Move onto the next HeapRegion_t structure. */\r
476                 xDefinedRegions++;\r
477                 pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );\r
478         }\r
479 \r
480         xMinimumEverFreeBytesRemaining = xTotalHeapSize;\r
481         xFreeBytesRemaining = xTotalHeapSize;\r
482 \r
483         /* Check something was actually defined before it is accessed. */\r
484         configASSERT( xTotalHeapSize );\r
485 \r
486         /* Work out the position of the top bit in a size_t variable. */\r
487         xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );\r
488 }\r
489 /*-----------------------------------------------------------*/\r
490 \r
491 void vPortGetHeapStats( HeapStats_t *pxHeapStats )\r
492 {\r
493 BlockLink_t *pxBlock;\r
494 size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */\r
495 \r
496         vTaskSuspendAll();\r
497         {\r
498                 pxBlock = xStart.pxNextFreeBlock;\r
499 \r
500                 /* pxBlock will be NULL if the heap has not been initialised.  The heap\r
501                 is initialised automatically when the first allocation is made. */\r
502                 if( pxBlock != NULL )\r
503                 {\r
504                         do\r
505                         {\r
506                                 /* Increment the number of blocks and record the largest block seen\r
507                                 so far. */\r
508                                 xBlocks++;\r
509 \r
510                                 if( pxBlock->xBlockSize > xMaxSize )\r
511                                 {\r
512                                         xMaxSize = pxBlock->xBlockSize;\r
513                                 }\r
514 \r
515                                 /* Heap five will have a zero sized block at the end of each\r
516                                 each region - the block is only used to link to the next\r
517                                 heap region so it not a real block. */\r
518                                 if( pxBlock->xBlockSize != 0 )\r
519                                 {\r
520                                         if( pxBlock->xBlockSize < xMinSize )\r
521                                         {\r
522                                                 xMinSize = pxBlock->xBlockSize;\r
523                                         }\r
524                                 }\r
525 \r
526                                 /* Move to the next block in the chain until the last block is\r
527                                 reached. */\r
528                                 pxBlock = pxBlock->pxNextFreeBlock;\r
529                         } while( pxBlock != pxEnd );\r
530                 }\r
531         }\r
532         xTaskResumeAll();\r
533 \r
534         pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;\r
535         pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;\r
536         pxHeapStats->xNumberOfFreeBlocks = xBlocks;\r
537 \r
538         taskENTER_CRITICAL();\r
539         {\r
540                 pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;\r
541                 pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;\r
542                 pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;\r
543                 pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;\r
544         }\r
545         taskEXIT_CRITICAL();\r
546 }\r
547 \r