freeRTOS源码解析1--堆栈管理1

freeRTOS源码解析1--堆栈管理1

freeRTOS有5种方式管理内存,源码路径:FreeRTOS\portable\MemMang,每种方式为1个.c文件--heap_1.c~heap_5.c。

本人暂时只了解了heap_4.c的管理方式,若有理解不到位的地方,请指正。

从申请内存函数:pvPortMalloc开始逐步解析,首先是源代码:

  1   1 void * pvPortMalloc( size_t xWantedSize )
  2   2 {
  3   3     BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
  4   4     void * pvReturn = NULL;
  5   5 
  6   6     vTaskSuspendAll();
  7   7     {
  8   8         /* If this is the first call to malloc then the heap will require
  9   9          * initialisation to setup the list of free blocks. */
 10  10         /* 如果是第一次调用,那么堆会请求初始化来创建空闲内存块的链表 */
 11  11         if( pxEnd == NULL )
 12  12         {
 13  13             prvHeapInit();
 14  14         }
 15  15         else
 16  16         {
 17  17             mtCOVERAGE_TEST_MARKER();
 18  18         }
 19  19 
 20  20         /* Check the requested block size is not so large that the top bit is
 21  21          * set.  The top bit of the block size member of the BlockLink_t structure
 22  22          * is used to determine who owns the block - the application or the
 23  23          * kernel, so it must be free. */
 24  24         /* 检查申请的块大小是否大到最高比特位置位了。结构体BlockLink_t中
 25  25            指示块大小的成员的最高比特位用于确定是谁拥有该内存块 - 应用程序还是内核,
 26  26            因此该位必须是空闲的 */
 27  27         if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
 28  28         {
 29  29             /* The wanted size must be increased so it can contain a BlockLink_t
 30  30              * structure in addition to the requested amount of bytes. */
 31  31             /* 请求的块大小必须增加,这样除了请求的字节数外,还能包含BlockLink_t结构体 */
 32  32             if( ( xWantedSize > 0 ) &&
 33  33                 ( ( xWantedSize + xHeapStructSize ) >  xWantedSize ) ) /* Overflow check */
 34  34             {
 35  35                 xWantedSize += xHeapStructSize;
 36  36 
 37  37                 /* Ensure that blocks are always aligned. */
 38  38                 /* 确保块始终是对齐的(8字节对齐) */
 39  39                 if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
 40  40                 {
 41  41                     /* Byte alignment required. Check for overflow. */
 42  42                     /* 需要字节对齐。检查溢出。 */
 43  43                     if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) )
 44  44                             > xWantedSize )
 45  45                     {
 46  46                         xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
 47  47                         configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
 48  48                     }
 49  49                     else
 50  50                     {
 51  51                         xWantedSize = 0;
 52  52                     }
 53  53                 }
 54  54                 else
 55  55                 {
 56  56                     mtCOVERAGE_TEST_MARKER();
 57  57                 }
 58  58             }
 59  59             else
 60  60             {
 61  61                 xWantedSize = 0;
 62  62             }
 63  63 
 64  64             if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
 65  65             {
 66  66                 /* Traverse the list from the start (lowest address) block until
 67  67                  * one of adequate size is found. */
 68  68                 /* 从头部块(最低地址)开始遍历列表,直到找到一个足够大的块 */
 69  69                 pxPreviousBlock = &xStart;
 70  70                 pxBlock = xStart.pxNextFreeBlock;
 71  71 
 72  72                 while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
 73  73                 {
 74  74                     pxPreviousBlock = pxBlock;
 75  75                     pxBlock = pxBlock->pxNextFreeBlock;
 76  76                 }
 77  77 
 78  78                 /* If the end marker was reached then a block of adequate size
 79  79                  * was not found. */
 80  80                 /* 如果遍历到了接尾块,那么无法找到一个足够大的块 */
 81  81                 if( pxBlock != pxEnd )
 82  82                 {
 83  83                     /* Return the memory space pointed to - jumping over the
 84  84                      * BlockLink_t structure at its start. */
 85  85                     /* 返回指向的内存空间——跳过头部的BlockLink_t结构体。 */
 86  86                     pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
 87  87 
 88  88                     /* This block is being returned for use so must be taken out
 89  89                      * of the list of free blocks. */
 90  90                     /* 此块要被返回使用,所以必须移出空闲块的链表 */
 91  91                     pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
 92  92 
 93  93                     /* If the block is larger than required it can be split into
 94  94                      * two. */
 95  95                     /* 如果此块大于申请的内存,那么可以拆分成两个块 */
 96  96                     if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
 97  97                     {
 98  98                         /* This block is to be split into two.  Create a new
 99  99                          * block following the number of bytes requested. The void
100 100                          * cast is used to prevent byte alignment warnings from the
101 101                          * compiler. */
102 102                         /* 此块要被分成两个块。创建一个紧随申请空间后的新块。强制转换成
103 103                            void以防止编译器上报字节对齐警告。 */
104 104                         pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
105 105                         configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
106 106 
107 107                         /* Calculate the sizes of two blocks split from the
108 108                          * single block. */
109 109                         /* 计算从单个块中分离出的两个块的大小。 */
110 110                         pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
111 111                         pxBlock->xBlockSize = xWantedSize;
112 112 
113 113                         /* Insert the new block into the list of free blocks. */
114 114                         /* 将新块插入到空闲块列表中。 */
115 115                         prvInsertBlockIntoFreeList( pxNewBlockLink );
116 116                     }
117 117                     else
118 118                     {
119 119                         mtCOVERAGE_TEST_MARKER();
120 120                     }
121 121 
122 122                     xFreeBytesRemaining -= pxBlock->xBlockSize;
123 123 
124 124                     if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
125 125                     {
126 126                         xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
127 127                     }
128 128                     else
129 129                     {
130 130                         mtCOVERAGE_TEST_MARKER();
131 131                     }
132 132 
133 133                     /* The block is being returned - it is allocated and owned
134 134                      * by the application and has no "next" block. */
135 135                     /* 此块将被返回--被分配并为应用程序所持有,并且此块没有指向“下一块”。 */
136 136                     pxBlock->xBlockSize |= xBlockAllocatedBit;
137 137                     pxBlock->pxNextFreeBlock = NULL;
138 138                     xNumberOfSuccessfulAllocations++;
139 139                 }
140 140                 else
141 141                 {
142 142                     mtCOVERAGE_TEST_MARKER();
143 143                 }
144 144             }
145 145             else
146 146             {
147 147                 mtCOVERAGE_TEST_MARKER();
148 148             }
149 149         }
150 150         else
151 151         {
152 152             mtCOVERAGE_TEST_MARKER();
153 153         }
154 154 
155 155         traceMALLOC( pvReturn, xWantedSize );
156 156     }
157 157     ( void ) xTaskResumeAll();
158 158 
159 159     #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
160 160         {
161 161             if( pvReturn == NULL )
162 162             {
163 163                 extern void vApplicationMallocFailedHook( void );
164 164                 vApplicationMallocFailedHook();
165 165             }
166 166             else
167 167             {
168 168                 mtCOVERAGE_TEST_MARKER();
169 169             }
170 170         }
171 171     #endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
172 172 
173 173     configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
174 174     return pvReturn;
175 175 }
View Code

以下开始逐行分析代码:

 vTaskSuspendAll();  // 暂停调度器

if( pxEnd == NULL )  // 第一次运行的话,pxEnd为NULL,走下面分支
{
  prvHeapInit();
}

prvHeapInit():

 1 static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
 2 {
 3     BlockLink_t * pxFirstFreeBlock;
 4     uint8_t * pucAlignedHeap;
 5     size_t uxAddress;
 6     size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
 7 
 8     /* Ensure the heap starts on a correctly aligned boundary. */
 9     /* 确保堆开始于对齐的边界上 */
10     // static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
11     // #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 75 * 1024 ) )
12     // ucHeap是一个很大的数组
13     // #define portBYTE_ALIGNMENT        8
14     // #define portBYTE_ALIGNMENT_MASK    ( 0x0007 )
15 
16     uxAddress = ( size_t ) ucHeap;
17     // uxAddress & 7非0,那么ucHeap起始地址未8字节对齐
18     // 用keil仿真时,我的uxAddress = 0x200001EC
19     if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
20     {
21         uxAddress += ( portBYTE_ALIGNMENT - 1 );                  // uxAddress = uxAddress + 7 = 0x200001F3
22         uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );     // uxAddress = uxAddress & 0xFFFFFFF8 = 0x200001F0
23         xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;          // xTotalHeapSize = 75k - (uxAddress - ucHeap) = 75k - 4
24     }
25     // 总空间少了4个字节,相当于堆的起始地址向后移动4个字节
26     // pucAlignedHeap = 0x200001F0 = 0x200001EC + 4
27     pucAlignedHeap = ( uint8_t * ) uxAddress;
28 
29     /* xStart is used to hold a pointer to the first item in the list of free
30      * blocks.  The void cast is used to prevent compiler warnings. */
31     /* xStart用于保存指向空闲链表的第一个链表项的指针。
32      * 强转成void是用于防止编译器报告警。 */
33     xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
34     xStart.xBlockSize = ( size_t ) 0;
35 
36     /* pxEnd is used to mark the end of the list of free blocks and is inserted
37      * at the end of the heap space. */
38     /* pxEnd用于标记空闲块链表的最后一项,并且被插入到堆空间的最后。 */
39     // const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( 8 - 1 ) ) ) & ~( ( size_t ) 7 );
40     // xHeapStructSize = (8 + 7) & 0xFFFFFFF8 = 8
41     // 堆的尾部也要进行对齐
42     uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;    // uxAddress = 0x200001F0 + 75k - 4 = 0x20012DEC
43     uxAddress -= xHeapStructSize;                                  // uxAddress = 0x20012DEC - 8 = 0x20012DE4
44     uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );          // uxAddress = 0x20012DE4 & 0xFFFFFFF8 = 0x20012DE0
45     pxEnd = ( void * ) uxAddress;
46     pxEnd->xBlockSize = 0;
47     pxEnd->pxNextFreeBlock = NULL;
48     // 堆的尾地址向前移动12个字节,其中前8个字节存放链表的最后一项,并用pxEnd指向该项
49 
50     /* To start with there is a single free block that is sized to take up the
51      * entire heap space, minus the space taken by pxEnd. */
52     /* 有一个空闲块,它的大小相当于整个堆空间,减去pxEnd占用的空间。 */
53     pxFirstFreeBlock = ( void * ) pucAlignedHeap;                             // 堆头部存放链表的第一项
54     pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;   // 可用的空闲堆空间(包含了该项的8个字节):75k-4-12=0x12BF0
55     pxFirstFreeBlock->pxNextFreeBlock = pxEnd;                                // 下一块指向尾部
56 
57     /* Only one block exists - and it covers the entire usable heap space. */
58     /* 只存在一个块,并且它包含整个可用的堆空间 */
59     xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;            // xMinimumEverFreeBytesRemaining = 0x12BF0
60     xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;                       // xFreeBytesRemaining = 0x12BF0
61 
62     /* Work out the position of the top bit in a size_t variable. */
63     /* 计算出size_t变量最高比特位的位置 */
64     // xBlockAllocatedBit = 1 << (8 *4 - 1) = 0x80000000
65     xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
66 }
View Code

执行完后,heap的示意图:

 

 

 

回到pvPortMalloc

 1 // 在prvHeapInit后,xBlockAllocatedBit就不再改变,将一直等于0x80000000
 2 // 假设xWantedSize = 105
 3 if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
 4 {
 5     if( ( xWantedSize > 0 ) && ( ( xWantedSize + xHeapStructSize ) >  xWantedSize ) ) /* Overflow check */
 6     {
 7         xWantedSize += xHeapStructSize;    // xWantedSize = xWantedSize + 8 = 0x71
 8 
 9         // 未对齐
10         if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
11         {
12             // (0x71 + (8 - (0x71 & 0x7))) = 0x78 > 0x71
13             if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) > xWantedSize )
14             {
15                 // xWantedSize = xWantedSize + (8 - (0x71 & 0x7)) = 0x78
16                 // 把想要的大小扩展7个字节,使其大小8字节对齐
17                 xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
18             }
19             else
20             {
21                 xWantedSize = 0;    // 加7后溢出了,则不会分配空间
22             }
23         }
24     }
25     else
26     {
27         xWantedSize = 0;           // 加8后溢出了,则不会分配空间
28     }
29 
30     // 第一次分配空间:xFreeBytesRemaining = 0x12BF0
31     if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
32     {
33         pxPreviousBlock = &xStart;
34         pxBlock = xStart.pxNextFreeBlock;    // pxBlock = 0x200001F0, pxBlock->pxNextFreeBlock = pxEnd, pxBlock->xBlockSize = 0x12BF0
35 
36         // 从头开始找足够大的空闲块
37         while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
38         {
39             pxPreviousBlock = pxBlock;
40             pxBlock = pxBlock->pxNextFreeBlock;
41         }
42 
43         // 已找到
44         if( pxBlock != pxEnd )
45         {
46             // pvReturn = pxBlock + 8 = 0x200001F0 + 8 = 0x200001F8
47             pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
48             // xStart.pxNextFreeBlock = pxEnd
49             pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
50             // #define heapMINIMUM_BLOCK_SIZE    ( ( size_t ) ( xHeapStructSize << 1 ) )
51             // 剩下的空闲空间大于16
52             if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
53             {
54                 // pxNewBlockLink = 0x200001F0 + 0x78 = 0x20000268
55                 pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
56                 // pxNewBlockLink->xBlockSize = 0x12BF0 - 0x78 = 0x12B78, pxBlock->xBlockSize = 0x78
57                 pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
58                 pxBlock->xBlockSize = xWantedSize;
59                 // 插入进空闲块链表
60                 prvInsertBlockIntoFreeList( pxNewBlockLink );
61             }
62             else
63             {
64                 mtCOVERAGE_TEST_MARKER();
65             }
66             // xFreeBytesRemaining = xFreeBytesRemaining - 0x78 = 0x12B78
67             xFreeBytesRemaining -= pxBlock->xBlockSize;
68             // xMinimumEverFreeBytesRemaining = 0x12BF0
69             if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
70             {
71                 xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;  // xMinimumEverFreeBytesRemaining = 0x12B78
72             }
73             else
74             {
75                 mtCOVERAGE_TEST_MARKER();
76             }
77 
78             pxBlock->xBlockSize |= xBlockAllocatedBit;  // pxBlock->xBlockSize = 0x78 | 0x80000000
79             pxBlock->pxNextFreeBlock = NULL;
80             xNumberOfSuccessfulAllocations++;           // xNumberOfSuccessfulAllocations = 1
81         }
82         else
83         {
84             mtCOVERAGE_TEST_MARKER();
85         }
86     }
87 }
88 ( void ) xTaskResumeAll();                              // 打开调度器
View Code

里面还有一个函数需要解析:prvInsertBlockIntoFreeList()

 1 static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
 2 {
 3     BlockLink_t * pxIterator;
 4     uint8_t * puc;
 5 
 6     /* Iterate through the list until a block is found that has a higher address
 7      * than the block being inserted. */
 8     /* 遍历列表,直到发现一个块的地址高于被插入的块的地址 */
 9     // pxBlockToInsert = 0x20000268
10     for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
11     {
12         /* Nothing to do here, just iterate to the right position. */
13         /* 什么都不做,只遍历 */
14     }
15 
16     /* Do the block being inserted, and the block it is being inserted after
17      * make a contiguous block of memory? */
18     /* 被插入的块和被插入后的块是否构成一个连续的内存块? */
19     // puc = pxIterator = &xStart
20     puc = ( uint8_t * ) pxIterator;
21 
22     // puc + xStart.xBlockSize = puc + 0 = puc = &xStart
23     if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
24     {
25         pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
26         pxBlockToInsert = pxIterator;
27     }
28     else
29     {
30         mtCOVERAGE_TEST_MARKER();
31     }
32 
33     /* Do the block being inserted, and the block it is being inserted before
34      * make a contiguous block of memory? */
35     /* 被插入的块和被插入后的块是否构成一个连续的内存块? */
36     // puc = 0x20000268
37     puc = ( uint8_t * ) pxBlockToInsert;
38 
39     // puc + pxBlockToInsert->xBlockSize = puc + 0x12B78 = 0x20012DE0 = pxEnd = pxIterator->pxNextFreeBlock
40     if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
41     {
42         if( pxIterator->pxNextFreeBlock != pxEnd )
43         {
44             /* Form one big block from the two blocks. */
45             pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
46             pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
47         }
48         else
49         {
50             pxBlockToInsert->pxNextFreeBlock = pxEnd;
51         }
52     }
53     else
54     {
55         pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
56     }
57 
58     /* If the block being inserted plugged a gab, so was merged with the block
59      * before and the block after, then it's pxNextFreeBlock pointer will have
60      * already been set, and should not be set here as that would make it point
61      * to itself. */
62     /* 如果插入的块产生一个间隙,则会将相连的块合并,
63      * 那么它的pxNextFreeBlock指针已被设置,不应该在这里设置,否则会使它指向自己 */
64     if( pxIterator != pxBlockToInsert )
65     {
66         pxIterator->pxNextFreeBlock = pxBlockToInsert;
67     }
68     else
69     {
70         mtCOVERAGE_TEST_MARKER();
71     }
72 }
View Code

全部执行完后,heap的示意图(首次执行pvPortMalloc):

 

 

首次执行pvPortMalloc,就分析到这里,下次分析首次释放。

posted @ 2022-09-27 17:18  freeManX1807  阅读(425)  评论(0编辑  收藏  举报