ucos中OSMemCreate()函数难点解析

  1.     该函数的功能是创建一块内存分区,并通过内存控制块指针来管理,具体功能为:堆内存addr地址处已经分配了一块连续内存分区,将该内存分区划分为blksize大小的不同内存块来管理,并配置内存块管理结构指针pmem。
  2. 函数源码如下:
  3. OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)
  4. {
  5. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  6.     OS_CPU_SR cpu_sr;
  7. #endif 
  8.     OS_MEM *pmem;
  9.     INT8U *pblk;
  10.     void **plink;
  11.     INT32U i;

  12. #if OS_ARG_CHK_EN > 0
  13.     if (addr == (void *)0) { /* Must pass a valid address for the memory part. */
  14.         *err = OS_MEM_INVALID_ADDR;
  15.         return ((OS_MEM *)0);
  16.     }
  17.     if (nblks < 2) { /* Must have at least 2 blocks per partition */
  18.         *err = OS_MEM_INVALID_BLKS;
  19.         return ((OS_MEM *)0);
  20.     }
  21.     if (blksize < sizeof(void *)) { /* Must contain space for at least a pointer */
  22.         *err = OS_MEM_INVALID_SIZE;
  23.         return ((OS_MEM *)0);
  24.     }
  25. #endif
  26.     
  27.     OS_ENTER_CRITICAL();
  28.     pmem = OSMemFreeList;                              /* Get next free memory partition */
  29.     if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */
  30.         OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
  31.     }
  32.     OS_EXIT_CRITICAL();
  33.     if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */
  34.         *err = OS_MEM_INVALID_PART;
  35.         return ((OS_MEM *)0);
  36.     }
  37.     /*
  38.         将一个分区的各个内存小块链接起来,形成一个链表
  39.     */
  40.     plink = (void **)addr; /* Create linked list of free memory blocks */
  41.     pblk = (INT8U *)addr + blksize;
  42.     for (= 0; i < (nblks - 1); i++) {
  43.         *plink = (void *)pblk;
  44.         plink = (void **)pblk;
  45.         pblk = pblk + blksize;
  46.     }
  47.     *plink = (void *)0; /* Last memory block points to NULL */

  48.     pmem->OSMemAddr = addr; /* Store start address of memory partition */

  49.     pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */

  50.     pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */

  51.     pmem->OSMemNBlks = nblks;

  52.     pmem->OSMemBlkSize = blksize; /* Store block size of each memory blocks */
  53.     *err = OS_NO_ERR;
  54.     return (pmem);
  55. }
  56.     该函数的巧妙之处,也即难理解之处便在于:将addr起始的内存块以balcksize大小分块,并在每一块的起始地址处保存一个地址(指针变量),该地址(指针)指向下一内存块的起始地址,即以单链表的形式管理该内存分区的每一块内存块。
  57. 由于要在每一内存块起始地址保存一个地址,那么很显然,我们需要一个二级地址来保存指向下一内存块的地址。
  58.     下边以串联一个内存块为例讲解:
  59.     void **plink = (void **)addr;解析:addr即为该内存分区首地址,将其强制转换为二级指针并赋值给plink,则plink也指向该分区首地址。这里最不好理解的是*plink是什么。为什么是这样呢?这里要好好思考一下将一级指针强制转换为二级指针的过程。以下图为例进行讲解:假设内存分区起始地址0x20000000,该内存中存储为0x12.....,此时,addr中存储的是0x12的地址,即首内存分区地址0x20000000,以此类推。

  60. 一旦执行void **plink = (void **)addr之后,从首地址开始的4字节内存中存储的数据被解释为地址指针),但是这个地址是无意义的,我们正需要将该地址改写为下一内存块的地址,即通过这两句实现:pblk = (INT8U *)addr + blksize;*plink = (void *)pblk;(如下图所示)
  61.  
  62. 以上便是一次链接内存块的过程。 在执行plink = (void **)pblk;之后,重复执行上一步,即可实现对整个内存分区所有内存块的串联。
  63. 最终串联完所有内存块后,*plink = (void *)0; 指针为空,表示下一内存块不存在,链表链接完成。
            终于写完了,虽然花了点时间,但是自己完全搞懂了,希望能帮助所有在这里遇到困难的朋友!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值