1 /*
2 *************************************************************************************************
3 * uC/OS-II实时控制内核
4 * 主要的包含文件
5 * --内存管理项代码--
6 *
7 * 文 件: OS_MEM.C 内存管理项代码
8 * 作 者: Jean J. Labrosse
9 * 中文注解: 钟常慰 zhongcw @ 126.com 整理:lin-credible 译注版本:1.0 请尊重原版内容
10 *************************************************************************************************
11 */
12
13 #ifndef OS_MASTER_FILE //是否已定义OS_MASTER_FILE主文件
14 #include "includes.h" //包含"includes.h"文件,部分C语言头文件的汇总打包文件
15 #endif //定义结束
16
17 #if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0) //若两个条件满足时,产生以下代码
18 //OS_MEM_EN允许 (1) 或者禁止 (0) 产生内存相关代码
19 //OS_MAX_MEM_PART 最多内存块的数目
20 *************************************************************************************************
21 * 建立并初始化一块内存区(CREATE A MEMORY PARTITION)
22 *
23 * 描述: 建立并初始化一块内存区。一块内存区包含指定数目的大小确定的内存块。程序可以包含这些内存
24 * 块并在用完后释放回内存区。
25 *
26 * 参数: addr 建立的内存区的起始地址。内存区可以使用静态数组或在初始化时使用malloc()函数建立。
27 *
28 * nblks 需要的内存块的数目。每一个内存区最少需要定义两个内存块。
29 *
30 * blksize 每个内存块的大小,最少应该能够容纳一个指针。
31 *
32 * err 是指向包含错误码的变量的指针。OSMemCreate()函数返回的错误码可能为下述几种:
33 * OS_NO_ERR 成功建立内存区;
34 * OS_MEM_INVALID_ADDR 非法地址,即地址为空指针;
35 * OS_MEM_INVALID_PART 没有空闲的内存区;
36 * OS_MEM_INVALID_BLKS 没有为每一个内存区建立至少2个内存块;
37 * OS_MEM_INVALID_SIZE 内存块大小不足以容纳一个指针变量。
38 * 返回: 返回指向内存区控制块的指针。如果没有剩余内存区,OSMemCreate()函数返回空指针。
39 *
40 * 注意: 必须首先建立内存区,然后使用
41 *************************************************************************************************
42 */
43 //建立并初始化一块内存区(起始地址、需要的内存块数目、每块内存块大小、返回错误的指针)
44 OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)
45 {
46 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
47 OS_CPU_SR cpu_sr;
48 #endif
49 OS_MEM *pmem; //内存控制块指针
50 INT8U *pblk; //每块内存块的起始地址
51 void **plink; //链接起始地址
52 INT32U i; //内存包含的内存区数量
53
54
55 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内
56 if (addr == (void *)0) { //当内存起始地址为0时
57 *err = OS_MEM_INVALID_ADDR; //错误显示为(非法地址,即地址为空指针,无效)
58 return ((OS_MEM *)0);
59 }
60 if (nblks < 2) { //每个内存分区至少有两个内存块
61 *err = OS_MEM_INVALID_BLKS; //否则显示(没有为每一个内存区建立至少2个内存块)
62 return ((OS_MEM *)0);
63 }
64 if (blksize < sizeof(void *)) { //每个内存块至少容得一个指针(链接指针)
65 *err = OS_MEM_INVALID_SIZE; //否则显示(内存块大小不足以容纳一个指针变量)
66 return ((OS_MEM *)0);
67 }
68 #endif
69 OS_ENTER_CRITICAL(); //关闭中断
70 pmem = OSMemFreeList; //内存控制块指针=空余内存控制块(链接)
71 if (OSMemFreeList != (OS_MEM *)0) { //当内存链接控制块≠0,即有空余控制块
72 OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList; //指向下一个空余链接控制块
73 }
74 OS_EXIT_CRITICAL(); //打开中断
75 if (pmem == (OS_MEM *)0) { //判断是否有空余内存控制块(为1有)
76 *err = OS_MEM_INVALID_PART; //没有空闲的内存区
77 return ((OS_MEM *)0); //返回Null,建立内存失败
78 }
79 plink = (void **)addr; //链接起始地址=内存分区起始地址
80 pblk = (INT8U *)addr + blksize; //每块内存的起始地址=内存分区起始地址+每块内存块大小
81 for (i = 0; i < (nblks - 1); i++) { //循环体(需要的内存块数目(次数))?
82 *plink = (void *)pblk; //链接起始地址(内容)=每块内存块的起始地址(内容)?
83 plink = (void **)pblk; //链接起始地址=内存块的起始地址指针(内容)?
84 pblk = pblk + blksize; //内存块的起始地址=自己+每块内存块大小?
85 }
86 *plink = (void *)0; //链接起始地址=0
87 OS_ENTER_CRITICAL(); //关闭中断
88 pmem->OSMemAddr = addr; //内存区指针=分区起始地址
89 pmem->OSMemFreeList = addr; //下一空余控制块=分区起始地址
90 pmem->OSMemNFree = nblks; //分区中内存块大小=需要的内存块数目
91 pmem->OSMemNBlks = nblks; //总的内存块数量=需要的内存块数目
92 pmem->OSMemBlkSize = blksize; //空余内存块数量=每块内存块大小
93 OS_EXIT_CRITICAL(); //打开中断
94 *err = OS_NO_ERR; //成功建立内存区
95 return (pmem); //返回(内存控制块指针)
96 }
97 /*$PAGE*/
98 /*
99 *************************************************************************************************
100 * 从内存区分配一个内存块(GET A MEMORY BLOCK)
101 *
102 * 描述: 用于从内存区分配一个内存块。用户程序必须知道所建立的内存块的大小,同时用户程序必须在使
103 * 用完内存块后释放内存块。使用OSMemGet()函数释放内存块。可以多次调用OSMemGet()函数。
104 *
105 * 参数: pmem 是指向内存区控制块的指针,可以从OSMemCreate()函数返回得到。
106 *
107 * err 是指向包含错误码的变量的指针。OSMemGet()函数返回的错误码可能为下述几种:
108 * OS_NO_ERR 成功得到一个内存块;
109 * OS_MEM_NO_FREE_BLKS 内存区已经没有空间分配给内存块;
110 * OS_MEM_INVALID_PMEM 'pmem'是空指针。
111 *
112 * 返回: 返回指向内存区块的指针。如果没有空间分配给内存块,OSMemGet()函数返回空指针。
113 *
114 * 注意: 必须首先建立内存区,然后使用
115 *************************************************************************************************
116 */
117
118 void *OSMemGet (OS_MEM *pmem, INT8U *err) //从内存区分配一个内存块(内存区控制块的指针、错误指针)
119 {
120 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
121 OS_CPU_SR cpu_sr;
122 #endif
123 void *pblk; //内存块的起始地址
124
125 #if OS_ARG_CHK_EN > 0 //所有的参数都是在指定的范围内
126 if (pmem == (OS_MEM *)0) { //指向内存区控制块的指针不能为空指针
127 *err = OS_MEM_INVALID_PMEM; //'pmem'是空指针
128 return ((OS_MEM *)0); //返回Null
129 }
130 #endif
131 OS_ENTER_CRITICAL(); //关闭中断
132 if (pmem->OSMemNFree > 0) { //检查内存分区中是否有空余的内存块(必须大于0)
133 pblk = pmem->OSMemFreeList; //刷新空余内存块链接表
134 pmem->OSMemFreeList = *(void **)pblk; //将链接表头指针后移1个元素
135 pmem->OSMemNFree--; //将空余内存块数减1
136 OS_EXIT_CRITICAL(); //打开中断
137 *err = OS_NO_ERR; //成功得到一个内存块
138 return (pblk); //返回(内存块的起始地址)
139 }
140 OS_EXIT_CRITICAL(); //打开中断
141 *err = OS_MEM_NO_FREE_BLKS; //内存区已经没有空间分配给内存块
142 return ((void *)0); //返回(没有空间分配给内存块)
143 }
144 /*$PAGE*/
145 /*
146 *************************************************************************************************
147 * 释放一个内存块 (RELEASE A MEMORY BLOCK)
148 *
149 * 描述: 释放一个内存块,内存块必须释放回原先申请的内存区。
150 *
151 * 参数: pmem 是指向内存区控制块的指针,可以从OSMemCreate()函数 返回得到。
152 *
153 * pblk 是指向将被释放的内存块的指针。
154 *
155 * 返回: OS_NO_ERR 成功释放内存块;
156 * OS_MEM_FULL 内存区已经不能再接受更多释放的内存块。这种情况说明用户程序出现
157 * 了错误,释放了多于用OSMemGet()函数得到的内存块
158 * OS_MEM_INVALID_PMEM 'pmem'是空指针;
159 * OS_MEM_INVALID_PBLK //指向将被释放的内存块的指针不能为空指针
160 *
161 * 注意: 1)必须首先建立内存区,然后使用;
162 * 2)内存块必须释放回原先申请的内存区。
163 *************************************************************************************************
164 */
165
166 INT8U OSMemPut (OS_MEM *pmem, void *pblk)
167 { //释放一个内存块(内存区控制块的指针、被释放的内存块的指针)
168 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
169 OS_CPU_SR cpu_sr;
170 #endif
171
172
173 #if OS_ARG_CHK_EN > 0 //所有的参数都是在指定的范围内
174 if (pmem == (OS_MEM *)0) { //指向内存区控制块的指针不能为空指针
175 return (OS_MEM_INVALID_PMEM); //'pmem'是空指针
176 }
177 if (pblk == (void *)0) { //指向将被释放的内存块的指针不能为空指针
178 return (OS_MEM_INVALID_PBLK); //'pblk'是空指针
179 }
180 #endif
181 OS_ENTER_CRITICAL(); //关闭中断
182 if (pmem->OSMemNFree >= pmem->OSMemNBlks) { //分区中内存块大小 >= 总的内存块数量(已满)
183 OS_EXIT_CRITICAL(); //打开中断
184 return (OS_MEM_FULL); //内存区已经不能再接受更多释放的内存块
185 }
186 //如果未满,将释放的内存块插入到该分区的空余内存块链接表中
187 *(void **)pblk = pmem->OSMemFreeList;
188 pmem->OSMemFreeList = pblk; //将链接表头指针指向被释放的内存块的指针
189 pmem->OSMemNFree++; //将分区中空余的内存块总数加1
190 OS_EXIT_CRITICAL();
191 return (OS_NO_ERR); //成功释放内存块
192 }
193 /*$PAGE*/
194 /*
195 *************************************************************************************************
196 * 得到内存区的信息(QUERY MEMORY PARTITION)
197 *
198 * 描述: 得到内存区的信息。该函数返回OS_MEM结构包含的信息,但使用了一个新的OS_MEM_DATA的数据结
199 * 构。OS_MEM_DATA数据结构还包含了正被使用的内存块数目的域。
200 *
201 * 参数: pmem 是指向内存区控制块的指针,可以从OSMemCreate()函数 返回得到。
202 *
203 * pdata 是指向OS_MEM_DATA数据结构的指针,该数据结构包含了以下的域:
204 * Void OSAddr; //指向内存区起始地址的指针
205 * Void OSFreeList; //指向空闲内存块列表起始地址的指针
206 * INT32U OSBlkSize; //每个内存块的大小
207 * INT32U OSNBlks; //该内存区的内存块总数
208 * INT32U OSNFree; //空闲的内存块数目
209 * INT32U OSNUsed; //使用的内存块数目
210
211 *
212 * 返回: OS_NO_ERR 存储块有效,返回用户应用程序;
213 * OS_MEM_INVALID_PMEM 'pmem'是空指针;
214 * OS_MEM_INVALID_PDATA pdata是空指针。
215 *
216 * 注意: 1)必须首先建立内存区,然后使用;
217 *************************************************************************************************
218 */
219
220 #if OS_MEM_QUERY_EN > 0 //允许生成 OSMemQuery()函数
221 INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata)
222 { //查询内存区的信息(内存区控制块的指针、保存数据的指针)
223 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
224 OS_CPU_SR cpu_sr;
225 #endif
226
227 #if OS_ARG_CHK_EN > 0 //所有的参数都是在指定的范围内
228 if (pmem == (OS_MEM *)0) { //指向内存区控制块的指针不能为空指针
229 return (OS_MEM_INVALID_PMEM); //'pmem'是空指针
230 }
231 if (pdata == (OS_MEM_DATA *)0) { //指向数据存储的指针不能为空指针
232 return (OS_MEM_INVALID_PDATA); //pdata是空指针
233 }
234 #endif
235 OS_ENTER_CRITICAL(); //关闭中断
236 pdata->OSAddr = pmem->OSMemAddr; //保存内存区起始地址的指针
237 pdata->OSFreeList = pmem->OSMemFreeList; //保存空闲内存块列表起始地址的指针
238 pdata->OSBlkSize = pmem->OSMemBlkSize; //保存内存块的大小
239 pdata->OSNBlks = pmem->OSMemNBlks; //保存该内存区的内存块总数
240 pdata->OSNFree = pmem->OSMemNFree; //保存空闲的内存块数目
241 OS_EXIT_CRITICAL(); //代开中断
242 pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; //保存正在使用的内存块总数
243 return (OS_NO_ERR); //返回(存储块有效,返回用户应用程序)
244 }
245 #endif // OS_MEM_QUERY_EN
246 /*$PAGE*/
247 /*
248 *************************************************************************************************
249 * 初始化内存分区(INITIALIZE MEMORY PARTITION MANAGER)
250 *
251 * 描述: 这个函数是通过uC/OS-II初始化内存分区. 你的请求不能调用这个函数
252 *
253 * 参数: 无
254 *
255 * 返回: 无
256 *
257 * 注意: 这个函数是uC/OS-II函数,你不同调用它
258 *************************************************************************************************
259 */
260
261 void OS_MemInit (void) //初始化内存分区
262 {
263 #if OS_MAX_MEM_PART == 1 //最多内存块的数目为1时
264 OSMemFreeList = (OS_MEM *)&OSMemTbl[0]; //内存块链接表=内存块首地址
265 OSMemFreeList->OSMemFreeList = (void *)0; //内存块链接表=0
266 OSMemFreeList->OSMemAddr = (void *)0; //内存区起始地址的指针=0
267 OSMemFreeList->OSMemNFree = 0; //空闲的内存块数目=0
268 OSMemFreeList->OSMemNBlks = 0; //该内存区的内存块总数=0
269 OSMemFreeList->OSMemBlkSize = 0; //内存块的大小=0
270 #endif
271
272 #if OS_MAX_MEM_PART >= 2 //最多内存块的数目为多个时
273 OS_MEM *pmem; //定义内存区控制块的指针
274 INT16U i; //定义分区的内存数量
275
276
277 pmem = (OS_MEM *)&OSMemTbl[0]; //内存区控制块的指针=内存控制块(MCB)首地址
278 for (i = 0; i < (OS_MAX_MEM_PART - 1); i++) { //设定循环初始化(i次)
279 pmem->OSMemFreeList = (void *)&OSMemTbl[i+1]; //内存块链接表=内存块地址(对应的分区)
280 pmem->OSMemAddr = (void *)0; //内存区起始地址的指针=0
281 pmem->OSMemNFree = 0; //空闲的内存块数目=0
282 pmem->OSMemNBlks = 0; //该内存区的内存块总数=0
283 pmem->OSMemBlkSize = 0; //内存块的大小=0
284 pmem++;
285 }
286 pmem->OSMemFreeList = (void *)0; //初始化最后的内存块链接表
287 pmem->OSMemAddr = (void *)0; //内存区起始地址的指针=0
288 pmem->OSMemNFree = 0; //空闲的内存块数目=0
289 pmem->OSMemNBlks = 0; //该内存区的内存块总数=0
290 pmem->OSMemBlkSize = 0; //内存块的大小=0
291
292 OSMemFreeList = (OS_MEM *)&OSMemTbl[0]; //回到开始的内存块链接表
293 #endif
294 }
295 #endif //OS_MEM.C文件结束
296 ******************************************结束****************************************************
297