解析鸿蒙内核消息队列QueueMail接口的哼哈二将
摘要:本文带领大家一起剖析了鸿蒙轻内核的队列模块的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接口的哼哈二将的更多相关文章
- 阿里最新38道Java面试题解析(MyBatis+消息队列+Redis)
一.谈谈你对 MyBatis 的理解? 1. Mybatis是一个半ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动.创建连接.创建 ...
- 消息队列接口API(posix 接口和 system v接口)
消息队列 posix API 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.信号这种通信方式更像\"即时\"的通信方式,它要求接受信号的进程在某个时间范围内对信 ...
- RT-thread内核之消息队列
一.消息队列控制块:在include/rtdef.h中 #ifdef RT_USING_MESSAGEQUEUE /** * message queue structure */ struct rt_ ...
- spring boot Rabbitmq集成,延时消息队列实现
本篇主要记录Spring boot 集成Rabbitmq,分为两部分, 第一部分为创建普通消息队列, 第二部分为延时消息队列实现: spring boot提供对mq消息队列支持amqp相关包,引入即可 ...
- 【FreeRTOS学习04】小白都能懂的 Queue Management 消息队列使用详解
消息队列作为任务间同步扮演着必不可少的角色: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 相关文章 1 前言 2 xQUEUE 3 相关概念 3 ...
- 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 百篇博客分析OpenHarmony源码 | v18.04
百篇博客系列篇.本篇为: v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 51.c.h .o 前因后果相关篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 ...
- System V 消息队列 实例
前言: 消息队列是消息的链接表,存放在内核中,并由消息队列标识符标识.我们将称消息队列为 “队列”,其标识符为“队列I D”.msgget创建一个新队列或打开一个存在的队列; msgsnd向队列末端添 ...
- RabbitMQ 消息队列 应用
安装参考 详细介绍 学习参考 RabbitMQ 消息队列 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. M ...
- 剖析nsq消息队列目录
剖析nsq消息队列(一) 简介及去中心化实现原理 剖析nsq消息队列(二) 去中心化源码解析 剖析nsq消息队列(三) 消息传输的可靠性和持久化[一] 剖析nsq消息队列(三) 消息传输的可靠性和持久 ...
- 快速入门分布式消息队列之 RabbitMQ(1)
目录 目录 前言 简介 安装 RabbitMQ 基本对象概念 Message 消息 Producer 生产者 Consumer 消费者 Queue 队列 Exchange 交换机 Binding 绑定 ...
随机推荐
- My 2022
很久以前好像是想过要写这么一个东西的.然而时间已至却毫无思路,故拖延至今. 很充实的一年.但似乎是唯一除了 whk/OI 相关完全不知还能写些什么的一年呢.(笑) 本来想写些别的什么,又忽而发现所有想 ...
- codeforce 827div4
第一次在codeforce上打题,补一下题记录成长 D题 分析:求数组中两个互质的数的最大下标和: 思路:观察到数据范围n是2e5暴力做n^2会超时,再观察数据a[i]最大为1000,所以这2e5个数 ...
- P4870 [BalticOI 2009 Day1]甲虫 题解
题目链接 简要题意 在一个数轴上有 \(n\) 滴露水,每滴露水初始水量为 \(m\),每秒会蒸发一滴水,一个甲虫初始在原点,速度为 1,水能瞬间喝完,问它最多能喝到几滴水. 题目分析 对于这种移动区 ...
- 搓一个Pythonic list
总所周知,Python语言当中的list是可以存储不同类型的元素的,对应到现代C++当中,可以用std::variant或者std::any实现类似的功能.而Python官方的实现当中用到了二级指 ...
- ereere
发现没有main函数 搜索start发现有,不过f5后发现不太像 然后在字符串那里搜索flag,点进去,然后f5但是失败了,最后发现得先定位到对应的函数处才能f5 f5 逐个查看函数,找到sub_4 ...
- DP:摆动序列
问题描述 如果一个序列满足下面的性质,我们就将它称为摆动序列: 1. 序列中的所有数都是不大于k的正整数: 2. 序列中至少有两个数. 3. 序列中的数两两不相等: 4. 如果第i – 1个数比第i ...
- Hive的使用以及如何利用echarts实现可视化在前端页面展示(四)---连接idea使用echarts可视化界面
说来惭愧,我的javaweb烂得一批,其他步骤我还是很顺利地,这个最简单的,我遇到了一系列问题.只能说,有时候失败也是一种成功吧 这一步其实就是正常的jdbc,没什么可说明的,但是关于使用echart ...
- #ifndef、#define、#ifdef等命令在C#中的应用
1.#ifndef指令的理解 #ifndef是一个预处理指令,用于判断一个表示符是否被定义.如果该标识符未被定义,则执行条件编译中的代码块.否则,将跳过该代码块.下面是一个简单的粒子. 1 #ifnd ...
- 洛谷P2757 [国家集训队]等差子序列 (hash+线段树)
题目连接 这题只要令 $len=3$看是否符合即可.因为是一个 $1$到 $n$的排列,考虑数列中项,那么对于一个数 $x$,令 $k=\max(n-x, x-1)$,只要存在 $d\in(1,k)$ ...
- 开发环境搭建:CubeMX、Keil MDK-ARM、仿真器驱动程序
来源:成电<微机原理与嵌入式系统>漆强 第三章 STM32微控制器开发环境的搭建 一.STM32 CubeMX的安装 1.STM32 CubeMX的下载和安装 先安装java环境安装 下载 ...