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