uCOS2内存管理
第七、OSMemNameGet和OSMemNameSet函数说明 8
作者:JCY
来自09级安徽宿州学院电子创新实验室
此文中对uCOS2内核内存管理的个人理解,若有错误之处请指出,不胜感激!
第一、内存管理数据架构
uCOS2操作系统当中也有内存管理,看了里面的算法个人感觉我今后不会用uCOS2的内存功能。当我还没有看uCOS2的内存管理的时候,总感觉它很神秘,总是想知道uCOS2是如何进行内存的管理的以及如何使用内存管理功能,虽然以后我基本上不会用到它的内存管理功能,当时既然看了还是需要总结一下的。
内存管理的函数有OS_MemInit,OSMemCreate,OSMemGet,OSMemPut,OSMemQuery,OSMemNameSet,OSMemNameGet等!
在深入到存储器管理接口之前,首先要了解一下内存分区数据结构os_mem。
os_mem的数据结构成员如下:
表1 内存分区数据结构os_mem的成员说明
成员名 | 功能说明 |
OSMemAddr | 存储器分区的首地址。 |
OSMemFreeList | 当该分区还没有建立时,它指向下一个内存分区数据结构当该分区已经被使用,即不出在内存数据结构链表中, 它指向该内存分区中空闲内存块的首地址。 |
OSMemBlkSize | 内存分区当中内存块的大小,既内存块占了多少字节。(每个内存块当中内,存块所占字节不一样)。 |
OSMemNBlks | 该内存分区当中有多少内存块。 |
OSMemNFree | 该内存分区当中还没有使用的内存块。 |
OSMemName | 内存分区的名字。 |
其次是内存分区数据结构数组定义如下:
OS_EXT OS_MEM OSMemTbl[OS_MAX_MEM_PART];
该数组中的元素就是上面的OS_MEM类型的数据,该数组就是建立几个内存分区数据结构,然后OS_MAX_MEM_PART个内存分区数据结构交给uCOS2操作系统来管理,也就是说在编译的时候内存分区数据结构已经被编译了并且已经占用了RAM空间。其实在链表里的结点就是该数组中的数组元素。
再次是内存分区信息数据结构os_mem_data,这个数据结构是为了得到某一个内存分区的信息时,调用相关函数将内存的分区信息存储到该数据结构中,并通过函数参数返回给调用函数。
os_mem_data的数据成员如下:
表2内存分区信息数据结构os_mem_data的成员说明
成员名 | 功能说明 |
OSAddr | 存储器分区的首地址。 |
OSFreeList | 当该分区还没有建立时,它指向下一个内存分区数据结构当该分区已经被使用,即不出在内存数据结构链表中, 它指向该内存分区中空闲内存块的首地址。 |
OSBlkSize | 内存分区当中内存块的大小,既内存块占了多少字节。(每个内存块当中内,存块所占字节不一样)。 |
OSNBlks | 该内存分区当中有多少内存块。 |
OSNFree | 该内存分区当中还没有使用的内存块。 |
OSNUsed | 该内存分区当中已使用的内存块。 |
第二、OS_MemInit函数说明
在内存管理里面也就主要是用了上面这两个结构体,那就首先看看内存分区初始化函数OS_MemInit。
OS_MemInit的源代码如下图所示:
这部分代码也是很简单的。其实就是初始化内存分区数据结构链表。我画了一个图,个人感觉此图可以反映这段代码的作用。
这段代码只是给出了OS_MemInit函数的作用,函数中代码分析在这里就不说了,如果以后只要有图示说明基本就不进行代码的讲解了。
第三、OSMemCreate函数说明
接下来看看OSMemCreate干了什么事情。
OSMemCreate的函数原型如下:
OS_MEM *OSMemCreate(void *addr,INT32U nblks,INT32U blksize,INT8U *perr)
它有四个参数,
参数 | 意义 |
addr | 要建立的内存分区的首地址 |
nblks | 将内存分区分了多少内存块 |
blksize | 内存块的大小 |
perr | 可能发生的错误信息 |
在此函数当中的核心的代码如下:
OS_ENTER_CRITICAL();
pmem = OSMemFreeList; /* Get next free memory partition */
if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */
OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
}
OS_EXIT_CRITICAL();
if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */
*perr = OS_ERR_MEM_INVALID_PART;
return ((OS_MEM *)0);
}
plink = (void **)addr; /* Create linked list of free memory blocks */
pblk = (INT8U *)((INT32U)addr + blksize);
for (i = 0; i < (nblks - 1); i++) {
*plink = (void *)pblk; /* Save pointer to NEXT block in CURRENT block */
plink = (void **)pblk; /* Position to NEXT block */
pblk = (INT8U *)((INT32U)pblk + blksize); /* Point to the FOLLOWING block */
}
*plink = (void *)0; /* Last memory block points to NULL */
pmem->OSMemAddr = addr; /* Store start address of memory partition */
pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */
pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */
pmem->OSMemNBlks = nblks;
pmem->OSMemBlkSize = blksize; /* Store block size of each memory blocks */
*perr = OS_ERR_NONE;
return (pmem);
程序当中的蓝色字体是为了判断是否还有空闲内存分区数据结构链表中是否还有可用的结点,若有就把该链表的表头从链表中取出。在接下来的程序当中就会为该内存分区数据结构当中的数据成员赋值。通过该内存分区数据结构可以知道所有的关于内存分区的信息。在调用其他的内存管理函数时,也是把该内存分区数据结构的指针作为内存管理函数的实参。
程序当中的红色部分是为了将内存分区当中的所有内存块通过各内存块的首地址连接起来。第一个内存块的首地址当中存放的是第二内存块的首地址,第二个内存块的首地址存放的是第三个内存块的首地址,依次类推,最后一个内存块的首地址指向为空,而OSMemFreeList 指向第一个内存控制块。这样就把内存分区当中的所有的内存块链接成一个链表了。
程序当中加有底纹的代码是对内存分区数据结构进行初始化。对于赋值的意义在此不再赘述。
第四、OSMemGet函数说明
下面就介绍一下OSMemGet函数的实现,与前面相同还是要把主要的代码显示在此处。
在OSMemGet函数中的核心代码如下:
此函数是将全局变量OSMemFreeList指向内存块链表的第一个内存块取出来,并将OSMemFreeList指向下一个内存块,并将OSMemNFree减一。函数的返回值为从链表中取出的内存块的首地址。如此操作就会从一个内存分区当中获得一个内存块了。
第五、OSMemPut函数说明
下面就介绍一下OSMemPut函数的实现,与前面相同还是要把主要的代码显示在此处。
在OSMemPut函数中的核心代码如下:
该函数的原型如下:
INT8U OSMemPut (OS_MEM *pmem, void *pblk)
pmem :通过此指针找到内存分区数据结构,然后就可以找到内存分区当中的所有的内存块了。
pblk :要释放的内存块的首地址
其实申请一个内存和释放一个内存是一个相反的过程。
首先将所要释放的内存块加入到OSMemNFree指向的链表的第一个位置,然后将内存分区数据结构当中的OSMemNFree成员加一。
第六、OSMemQuery函数说明
OSMemQuery是一个内存分区查询函数,通过此函数我们可以获得某一个内存分区的信息,例如:内存分区的大小,内存分区的内存块数量,可用内存块数等。
OSMemQuery函数原型如下:
INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *p_mem_data)
其中的OS_MEM_DATA数据结构已经在前面讲解了,其实该函数就是从该内存分区数据结构当中获得相关信息,然后在将信息存储到OS_MEM_DATA数据结构中。我个人感觉这是为了避免用户程序直接对内存分区数据结构操作,即禁止用户程序访问内核空间。
在OSMemQuery函数中的核心代码如下:
看到了此代码了吧?是不是非常简单。就是从内存分区数据结构获得数据,然后在存放到OS_MEM_DATA数据结构当中。
第七、OSMemNameGet和OSMemNameSet函数说明
uCOS2也可以给内存分区一个名字,当时这个功能好像在以前的uCOS2内核当中是没有的。我现在操作的内核是2.8.6版本。在此内核当中是可以使用内存名字的,并且用户可以对内核进行配置一决定使用或者不使用内核的内存分区名功能。
内存管理接口当中有两个函数是操作内存名的。一个是获得内存名,接口函数为OSMemNameGet,一个是设置内存名,接口函数为OSMemNameSet。由于两函数较为简单,在此不再叙述。