Ucos II 内存管理
在mcu21的项目里,暂时还没用到内存管理。不过还是有必要学习一下的。
为了消除内存碎片,ucos II 把连续的大块内存按分区来管理。每个分区中包含有整数个大小相同的内存块。
类似每个任务对应一个任务控制块,每个事件对应一个事件控制块,ucos II里每个内存块也是对应一个内存控制块。内存控制块是一个数据结构,定义如下:
typedef struct {
void *OSMemAddr;
void *OSMemFreeList;
INT32U OSMemBlkSize;
INT32U OSMemNBlks;
INT32U OSMemNFree;
} OS_MEM;
typedef struct {
void *OSMemAddr;
void *OSMemFreeList;
INT32U OSMemBlkSize;
INT32U OSMemNBlks;
INT32U OSMemNFree;
} OS_MEM;
.OSMemAddr是指向内存分区起始地址的指针。它在建立内存分区OSMemCreate()时被初始化,在此之后就不能更改了。
.OSMemFreeList是指向下一个空闲内存控制块或者下一个空闲的内存块的指针,具体含义要根据该内存分区是否已经建立来决定。
.OSMemBlkSize是内存分区中内存块的大小,是用户建立该内存分区时指定的。
.OSMemNBlks是内存分区中总的内存块数量,也是用户建立该内存分区时指定的。
.OSMemNFree是内存分区中当前可以得空闲内存块数量。
完整地使用内存,需要经过以下步骤:
1. 建立一个内存分区(OSMemCreate())
2. 调用OSMemGet()函数从已经建立的内存分区中申请内存块
3. 当用户应用程序不再使用一个内存块时,调用OSMemPut()释放内存。
4. 在这过程中可以调用OSMemQuery()查询一个内存分区的状态
建立一个内存分区需要使用ucos II 系统函数OSMemCreate()。实现过程如下:
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)
{
OS_MEM *pmem;
INT8U *pblk;
void **plink;
INT32U i;
if (nblks < 2) { (1)
*err = OS_MEM_INVALID_BLKS;
return ((OS_MEM *)0);
}
if (blksize < sizeof(void *)) { (2)
*err = OS_MEM_INVALID_SIZE;
return ((OS_MEM *)0);
}
OS_ENTER_CRITICAL();
pmem = OSMemFreeList; (3)
if (OSMemFreeList != (OS_MEM *)0) {
OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
}
OS_EXIT_CRITICAL();
if (pmem == (OS_MEM *)0) { (4)
*err = OS_MEM_INVALID_PART;
return ((OS_MEM *)0);
}
plink = (void **)addr; (5)
pblk = (INT8U *)addr + blksize;
for (i = 0; i < (nblks - 1); i++) {
*plink = (void *)pblk;
plink = (void **)pblk;
pblk = pblk + blksize;
}
*plink = (void *)0;
OS_ENTER_CRITICAL();
pmem->OSMemAddr = addr; (6)
pmem->OSMemFreeList = addr;
pmem->OSMemNFree = nblks;
pmem->OSMemNBlks = nblks;
pmem->OSMemBlkSize = blksize;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (pmem); (7)
该函数共有4个参数:内存分区的起始地址、分区内的内存块总块数、每个内存块的字节数和一个指向错误信息代码的指针。如果OSMemCreate()操作失败,它将返回一个NULL指针。否则,它将返回一个指向内存控制块的指针。对内存管理的其它操作,象OSMemGet(),OSMemPut(),OSMemQuery()函数等,都要通过该指针进行。
在mcu21的理解中,以上程序,简单来说,主要执行以下两大步骤,一是从空闲内存控制块中获取一个内存控制块,二是初始化这块内存控制块。