摘要:本文带领大家一起剖析了鸿蒙轻内核的队列模块的QueueMail两个接口的源代码。

本文分享自华为云社区《鸿蒙轻内核M核源码分析系列十三(续) 消息队列QueueMail接口》,作者:zhushy 。

之前分析过队列(Queue)的源代码,了解了队列初始化、队列创建、删除、队列读取写入等操作。队列还提供了两个接口OsQueueMailAlloc和OsQueueMailFree。队列可以和一个静态内存池关联起来,一个任务从静态内存池申请内存块时,如果申请不到,会把该任务插入到队列的内存阻塞链表中,等有其他任务释放内存时,该任务会被分配内存块。

接下来,详细看下这2个接口的源代码。

1、队列结构体定义

1.1 队列结构体定义

我们回忆下队列结构体的定义,在文件kernel\include\los_queue.h中定义队列控制块结构体为LosQueueCB,结构体源代码如下。需要看下成员变量memList,当任务从和队列关联的静态内存池中申请不到空闲内存块时,会把任务插入memList内存阻塞链表,然后调度,进行任务切换。等有其他任务释放空闲内存块到这个静态内存池时,该任务申请到空闲内存块,并把任务从memList内存阻塞链表移除,插入到任务就绪队列,并触发任务调度。

typedef struct {UINT8 *queue;      /**< 队列内存空间的指针 */UINT16 queueState; /**< 队列的使用状态 */UINT16 queueLen;   /**< 队列长度,即消息数量 */UINT16 queueSize;  /**< 消息节点大小 */UINT16 queueID;    /**< 队列编号  */UINT16 queueHead;  /**< 消息头节点位置 */UINT16 queueTail;  /**< 消息尾节点位置 */UINT16 readWriteableCnt[OS_READWRITE_LEN]; /**< 2维数组,可读、可写的消息数量, 0:可读, 1:可写 */LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /**< 2维双向链表数组,阻塞读、写任务的双向链表, 0:读链表, 1:写链表 */LOS_DL_LIST memList; /**< 内存节点双向链表 */
} LosQueueCB;

2、QueueMail接口源码分析

2.1 OsQueueMailAlloc接口

我们可以使用函数VOID *OsQueueMailAlloc(UINT32 queueID, VOID *mailPool, UINT32 timeOut)从和队列关联的静态内存池中申请空闲内存,下面通过分析源码看看如何申请内存。该函数需要3个参数,queueID是一个在使用状态的队列的编号,*mailPool是和队列关联的静态内存池地址,timeOut是超时时间,取值[0,LOS_WAIT_FOREVER]。该接口函数返回申请到的内存地址或者NULL。

⑴处开始对参数进行校验,⑵处根据队列编号获取队列控制结构体queueCB,然后校验该队列是否为使用状态。⑶处调用静态内存分配函数LOS_MemboxAlloc获取空闲内存块,然后获取的内存地址不为NULL,返回该内存块地址,否则执行后续代码。⑷处获取当前运行的任务控制结构体,⑸处把当前任务加入队列的内存阻塞链表queueCB->memList,然后触发任务调度。

等有其他其他任务调用OsQueueMailFree释放内存后,上述阻塞的任务获得内存块,或者因超时退出阻塞列表并调度运行后,会开始执行⑹处语句。⑺处表示因为超时返回,任务没有获取到内存块,跳转到END标签,返回NULL内存地址。⑻处表示获取到内存块,把任务的msg置空,并返回获取到的内存块的地址。

LITE_OS_SEC_TEXT VOID *OsQueueMailAlloc(UINT32 queueID, VOID *mailPool, UINT32 timeOut)
{VOID *mem = (VOID *)NULL;UINT32 intSave;LosQueueCB *queueCB = (LosQueueCB *)NULL;LosTaskCB *runTsk = (LosTaskCB *)NULL;⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {return NULL;}if (mailPool == NULL) {return NULL;}if (timeOut != LOS_NO_WAIT) {if (OS_INT_ACTIVE) {return NULL;}}intSave = LOS_IntLock();
⑵  queueCB = GET_QUEUE_HANDLE(queueID);if (queueCB->queueState == OS_QUEUE_UNUSED) {goto END;}⑶  mem = LOS_MemboxAlloc(mailPool);if (mem == NULL) {if (timeOut == LOS_NO_WAIT) {goto END;}⑷      runTsk = (LosTaskCB *)g_losTask.runTask;
⑸      OsSchedTaskWait(&queueCB->memList, timeOut);LOS_IntRestore(intSave);LOS_Schedule();⑹      intSave = LOS_IntLock();if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) {
⑺          runTsk->taskStatus &= (~OS_TASK_STATUS_TIMEOUT);goto END;} else {/* When enters the current branch, means the current task already got a available membox,* so the runTsk->msg can not be NULL.*/
⑻          mem = runTsk->msg;runTsk->msg = NULL;}}END:LOS_IntRestore(intSave);return mem;
}

2.2 OsQueueMailFree

我们可以使用函数UINT32 OsQueueMailFree(UINT32 queueID, VOID *mailPool, VOID *mailMem)释放空闲内存到和队列关联的静态内存池中,下面通过分析源码看看如何释放内存。该函数需要3个参数,queueID是一个在使用状态的队列的编号,*mailPool是和队列关联的静态内存池地址,*mailMem表示要释放的内存块地址。该接口返回值类型为无符号整数,表示是否成功或者错误码。

⑴处开始对参数进行校验。⑵处调用静态内存释放函数LOS_MemboxFree释放空闲内存块,如果释放失败,返回错误码。⑶处根据队列编号获取队列控制结构体queueCB,然后校验该队列是否为使用状态。成功释放内存后,如果队列的内存阻塞列表不为空,有阻塞任务,则执行⑷。⑸处从阻塞列表中获取第一个任务控制结构体,然后调用接口OsSchedTaskWake把任务从阻塞列表移除,并添加到任务就绪队列。⑹处从静态内存池申请一个内存块,如果申请失败返回错误码,否则执行⑺,把申请到的内存赋值到任务控制结构体的msg成员变量,然后触发调度。

LITE_OS_SEC_TEXT UINT32 OsQueueMailFree(UINT32 queueID, VOID *mailPool, VOID *mailMem)
{VOID *mem = (VOID *)NULL;UINT32 intSave;LosQueueCB *queueCB = (LosQueueCB *)NULL;LosTaskCB *resumedTask = (LosTaskCB *)NULL;⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {return LOS_ERRNO_QUEUE_MAIL_HANDLE_INVALID;}if (mailPool == NULL) {return LOS_ERRNO_QUEUE_MAIL_PTR_INVALID;}intSave = LOS_IntLock();⑵  if (LOS_MemboxFree(mailPool, mailMem)) {LOS_IntRestore(intSave);return LOS_ERRNO_QUEUE_MAIL_FREE_ERROR;}⑶  queueCB = GET_QUEUE_HANDLE(queueID);if (queueCB->queueState == OS_QUEUE_UNUSED) {LOS_IntRestore(intSave);return LOS_ERRNO_QUEUE_NOT_CREATE;}⑷  if (!LOS_ListEmpty(&queueCB->memList)) {
⑸      resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->memList));OsSchedTaskWake(resumedTask);
⑹      mem = LOS_MemboxAlloc(mailPool);if (mem == NULL) {LOS_IntRestore(intSave);return LOS_ERRNO_QUEUE_NO_MEMORY;}
⑺      resumedTask->msg = mem;LOS_IntRestore(intSave);LOS_Schedule();} else {LOS_IntRestore(intSave);}return LOS_OK;
}

小结

本文带领大家一起剖析了鸿蒙轻内核的队列模块的QueueMail两个接口的源代码。感谢阅读,如有任何问题、建议,都可以留言给我,谢谢。

点击关注,第一时间了解华为云新鲜技术~

解析鸿蒙内核消息队列QueueMail接口的哼哈二将相关推荐

  1. 鸿蒙系统源代码解析,鸿蒙内核源码分析(系统调用篇) | 图解系统调用全貌

    本篇说清楚系统调用 读本篇之前建议先读鸿蒙内核源码分析(总目录)工作模式篇. 本篇通过一张图和七段代码详细说明系统调用的整个过程,代码一捅到底,直到汇编层再也捅不下去. 先看图,这里的模式可以理解为空 ...

  2. System V 消息队列(一)—— 消息队列相关接口函数(msgget / msgctl)

    SystemV方案是在OS内核层面专门为进程间通信设计的一个方案,然后通过系统调用(system call)给用户提供通信接口.SystemV方案包含三种:共享内存.消息队列.信号量. 和System ...

  3. mybatis select语句会默认带排序吗_10月阿里最新38道Java面试题解析(MyBatis+消息队列+Redis)...

    MyBatis面试题 一.谈谈你对 MyBatis 的理解? 1. Mybatis是一个半ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加 ...

  4. 鸿蒙系统深度解析,深度解析鸿蒙内核最重要的结构体

    谁是鸿蒙内核最重要的结构体? 答案一定是:LOS_DL_LIST(双向链表),它长这样. typedef struct LOS_DL_LIST {//双向链表,内核最重要结构体 struct LOS_ ...

  5. MQ(消息队列)常见的应用场景解析

    MQ(消息队列)常见的应用场景解析 原文:MQ(消息队列)常见的应用场景解析 前言 提高系统性能首先考虑的是数据库的优化,之前一篇文章<数据库的使用你可能忽略了这些>中有提到过开发中,针对 ...

  6. 进程间通信——消息队列(Message queue)

    在Linux中,IPC消息队列是一个双向通信的全内存设计,即内核保证了读写顺序和数据同步,并且是性能比较好的先进先出的数据结构.消息队列的应用场景:比如异步任务处理,抢占式的数据分发,顺序缓存区等. ...

  7. 【消息队列】RocketMQ 基础知识扫盲

    一.前言 消息队列顾名思义就是存放消息的队列,所以问题并不是消息队列是什么,而是: 消息队列为什么会出现? 消息队列能用来干什么? 用它来干这些事会带来什么好处? 消息队列会带来副作用吗? 下面分别解 ...

  8. RT-Thread之消息队列

    消息队列的应用场景 消息队列是常用的线程间通信方式,是一种异步的通信方式.消息队列可以应用于多种场合:线程间的消息交换.在中断服务函数中给线程发送消息(中断服务例程不可能接收消息).使用串口接收不定长 ...

  9. RT-Thread 消息队列(学习笔记)

    本文参考自[野火EmbedFire]<RT-Thread内核实现与应用开发实战--基于STM32>,仅作为个人学习笔记.更详细的内容和步骤请查看原文(可到野火资料下载中心下载) 文章目录 ...

最新文章

  1. 前后端分离的探索(三)
  2. 证券一哥炼成记——郭树清
  3. 图像倒转90度(Rotate Image)
  4. 【LeetCode笔记】剑指 Offer 62. 圆圈中最后剩下的数字(Java、约瑟夫环、链表)
  5. 《魔兽世界插件》教程---21点扑克游戏 Blackjack
  6. cms查询系统(二)json形式参数的设计与解析
  7. c++枚举和c语言枚举_C语言枚举初学者指南
  8. java类验证和装载顺序_深度分析Java的ClassLoader机制(源码级别)
  9. CBDNet:Toward Convolutional Blind Denoising of Real Photographs
  10. 电子知识基础——电阻
  11. NOI2010:航空管制(拓扑排序 + 思维)
  12. 婚恋相亲交友短视频婚姻介绍所中介平台系统app公众号H5搭建源码
  13. [研一上]人脸属性迁移文献梳理(1)
  14. SQLOS任务调度算法
  15. 对学习数据结构的建议
  16. Win10突然卡死的原因调查(转自yzhang)
  17. iview表格表头上添加icon图标
  18. oppo手机安装应用失败,提示版本不兼容
  19. [解疑]图像、矩阵的二维空间变换
  20. 蚂蚁金服收购Kakao,完善移动金融布局

热门文章

  1. Bootstrap CSS编码规范之选择器使用规范
  2. es6 循环加载ES6模块
  3. VS2019C++代码出现cout不明确
  4. 视觉SLAM十四讲学习笔记专栏汇总
  5. microsoft符合服务器加载符号的解决方案
  6. c语言一元二次方程代码,一元二次方程求解程序完整代码
  7. Oracle DBA 经典面试题
  8. 用自己电脑做服务器,建个人网站
  9. Python 函数 -next()
  10. Python高手之路【十】python基础之反射