往期知识点记录:
- 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
- OpenHarmony轻量系统服务管理|鸿蒙业务模型重要概念详解
- OpenHarmony轻量系统服务管理|同进程及跨进程间通信的数据结构及过程详解
- OpenHarmony轻量系统服务管理|系统服务间调用之对外接口详解
- OpenHarmony轻量系统服务管理|系统服务管理之基础框架及功能详解
- OpenHarmony轻量系统服务管理|系统服务管理之系统功能管理器详解
- OpenHarmony轻量系统服务管理|消息广播服务及其子功能详解
- OpenHarmony轻量系统服务管理|消息广播功能实例操作详解(一)
- OpenHarmony轻量系统服务管理|消息广播功能实例操作详解(二)
- OpenHarmony POSIX和CMSIS接口适配层解读(1):queue_adapter
- OpenHarmony POSIX和CMSIS接口适配层解读adapter(2):thread/memory/time
- OpenHarmony轻量系统服务管理-samgr主要接口思维导图(1)
- OpenHarmony轻量系统服务管理-samgr主要接口思维导图(2)
- OpenHarmony轻量系统服务管理-samgr:common赏析及实现
- OpenHarmony轻量系统服务管理-samgr:iunknown赏析
- OpenHarmony轻量系统服务管理-samgr:iunknown实现分析
- OpenHarmony轻量系统服务管理samgr-message赏析
- OpenHarmony轻量系统服务管理samgr-message实现分析(1)
- 持续更新中……
一、前言
本文针对message中的相关函数的实现进行分析,相应的文件位于distributedschedule_samgr_lite\samgr\source\message.c。本部分消息通信的过程是基于消息队列来实现的,穿插了大量的消息队列操作,消息传递的对象是exchange,内部包含了request和response。
二、实现分析
- 结构体分析
//传递消息时的结构体
struct Exchange {
//目标服务或特性标识
Identity id;
//请求消息
Request request;
//响应消息
Response response;
//消息的类型
short type;
//异步响应或回调函数
Handler handler;
//用于共享请求和响应的引用计数
uint32 *sharedRef;
};
- 函数实现分析
发送请求操作
/*
函数功能:发送请求消息
函数参数:@identity:标识服务或特性的ID
@request:请求消息
@handler:消息的响应处理函数
函数返回:成功返回EC_SUCCESS,失败返回EC_INVALID or EC_BUSBUSY
函数描述:根据参数创建消息交换对象exchange,exchange对象是消息传递的载体。
将消息放入identity标识的消息队列中,完成消息的发送。
在消息传输前判断该消息是否指定回调函数handler。
若未指定,则在处理这条消息时不需要发送响应。若指定,则在处理完该消息后需要发送响应。
所以将当前线程绑定的消息队列ID赋给exchange对象的queueId,处理完消息后将响应消息发送到当前线程的消息队列中。
*/
int32 SAMGR_SendRequest(const Identity *identity, const Request *request, Handler handler)
{
//参数检查
if (request == NULL || identity == NULL) {
return EC_INVALID;
}
//创建exchange对象,用于传递消息,将请求消息放到指定的消息队列中
Exchange exchange = {*identity, *request, {NULL, 0}, MSG_NON, handler, NULL};
exchange.id.queueId = NULL;
if (handler != NULL) {
//handler不为NULL,即消息有响应处理函数
//获取当前的线程绑定的消息队列ID,这里的消息队列ID是线程创建时绑定的。
//当消息的处理者处理完消息并进行响应时,将响应消息对象发送到当前线程的消息队列中。
exchange.id.queueId = SAMGR_GetCurrentQueueID();
//类型表示当处理完消息需要发送响应给当前线程
exchange.type = MSG_CON;
}//若handler为NULL,则当前消息对象不存在消息的响应处理,类型为MSG_NON
//将请求放入队列,消息的处理需要调用对应的服务或功能的消息处理函数。
return QUEUE_Put(identity->queueId, &exchange, 0, DONT_WAIT);
}
发送响应操作
/*
函数功能:发送响应消息
函数参数:@request:请求消息
@response:响应消息
函数返回:成功返回EC_SUCCESS,失败返回EC_INVALID
函数描述:针对MSG_CON类型的消息发送响应。
若消息的响应处理函数handler==NULL,则不需要处理。
若不为空,则判断exchange->id.queueId的值,若为NULL,则无需发送到消息响应队列中,直接调用响应处理函数处理。
若exchange->id.queueId不为空,则将消息类型更新为MSG_ACK,然后发送到queueId中,由queueId对应的线程进行处理,这样exchange对象就由多个消息队列共享。
*/
int32 SAMGR_SendResponse(const Request *request, const Response *response)
{
//参数检查
if (request == NULL) {
return EC_INVALID;
}
//获取exchange对象
Exchange *exchange = GET_OBJECT(request, Exchange, request);
if (exchange->type != MSG_CON) {
//类型不是MSG_CON,则不发送响应,返回EC_INVALID
return EC_INVALID;
}
if (exchange->handler == NULL) {
//消息的响应处理函数==NULL,则不需要发送响应,返回EC_SUCCESS
return EC_SUCCESS;
}
//消息类型为MSG_CON,消息响应函数不为NULL
//更新当前消息类型为MSG_ACK确认
exchange->type = MSG_ACK;
//初始化响应数据
exchange->response.data = NULL;
exchange->response.len = 0;
if (response != NULL) {
exchange->response = *response;
}
//如果没有任务队列,则调用当前任务中的响应处理器。这里的队列是通过SAMGR_GetCurrentQueueID()获得的
if (exchange->id.queueId == NULL) {
exchange->handler(&exchange->request, &exchange->response);
return EC_SUCCESS;
}
//如果队列ID不为空,则调用sharedsend(),将消息对象放入指定的消息队列中(发送回原来的队列中),由它对应的线程进行处理。
//此时的exchange对象是共享的,即被两个或以上的消息队列引用
int32 ret = SharedSend(exchange->id.queueId, exchange, 1);
//如果队列已满,则直接调用消息的响应处理函数
if (ret != EC_SUCCESS) {
//不成功则调用当前任务中的响应处理器
exchange->handler(&exchange->request, &exchange->response);
//更新引用
(void)FreeReference(exchange);
}
return EC_SUCCESS;
}
接收消息操作
/*
函数功能:从消息队列接收消息
函数描述:从指定的消息队列中读取size大小的数据,拷贝到interMsg中。该操作为阻塞IO
*/
int32 SAMGR_MsgRecv(MQueueId queueId, uint8 *interMsg, uint32 size)
{
//参数检查
if (queueId == NULL || interMsg == NULL || size == 0) {
return EC_INVALID;
}
//将interMsg清空
if (memset_s(interMsg, size, 0x00, size) != EOK) {
return EC_FAILURE;
}
//消息出队,阻塞操作,直到出队成功
return QUEUE_Pop(queueId, interMsg, 0, WAIT_FOREVER);
}