本文继续对任务管理器的实现进行分析。
任务执行入口函数,当前函数是线程创建时的运行函数
/*
函数功能:循环读取消息队列中的消息,并处理
函数描述:不断的从绑定的消息队列中读取消息,根据消息的类型调用不同的处理函数。
在处理消息前,若serviceImpl的状态为SVC_IDLE,则更新为SVC_BUSY。
对于MSG_EXIT类型的消息,回收资源并退出线程。
对于MSG_ACK和MSG_DIRECT类型的消息,直接调用exchange的响应处理函数handler处理。
对于MSG_EXIT、MSG_ACK和MSG_DIRECT类型以外的消息,调用服务或子功能的消息处理函数处理。
消息处理完后,若serviceImpl的状态为SVC_BUSY,则更新为SVC_IDLE。
*/
static void *TaskEntry(void *argv)
{
ServiceImpl *serviceImpl = NULL;
//将消息队列ID存到当前线程的私有变量中。将当前线程与指定任务池中的消息队列绑定。
THREAD_SetThreadLocal(argv);
//循环处理消息队列中的消息
while (TRUE) {
Exchange exchange;
//从指定的消息队列接收消息,会因为QUEUE_Pop()函数而阻塞
uint32 msgRcvRet = SAMGR_MsgRecv((MQueueId)argv, (uint8 *)&exchange, sizeof(Exchange));
if (msgRcvRet != EC_SUCCESS) {
//读取消息失败
continue;
}
//消息接收成功
//消息类型为退出,退出当前线程
if (exchange.type == MSG_EXIT) {
//判断exchange对象的引用计数是否为0,若为0则释放request.data、response.data和sharedref所指向的动态内存,否则不会释放,只是引用计数减一
SAMGR_FreeMsg(&exchange);
break;
}
//通过接收到的exchange对象更新serviceImpl
serviceImpl = CorrectServiceImpl(&exchange, serviceImpl);
//更新ServiceImpl的消息处理数和时间戳,并更改状态为SVC_BUSY
BeginWork(serviceImpl);
//当消息类型为MSG_ACK时,执行响应处理函数
ProcResponse(&exchange);
//处理MSG_DIRECT类型的消息
ProcDirectRequest(&exchange);
//处理除MSG_ACK和MSG_DIRECT以外的消息
ProcRequest(&exchange, serviceImpl);
//消息处理结束,更新状态为SVC_IDLE
EndWork(serviceImpl, &exchange);
//判断exchange对象的引用计数是否为0,若为0则释放request.data、response.data和sharedref所指向的动态内存,否则不会释放,只是引用计数减一
SAMGR_FreeMsg(&exchange);
}
//退出时销毁消息队列
QUEUE_Destroy((MQueueId)argv);
return NULL;
}
处理MSG_NON/MSG_CON/MSG_SYNC类型的消息
//通过服务或子功能的消息处理函数处理MSG_NON/MSG_CON/MSG_SYNC类型的消息,当消息类型为MSG_CON时,发送相应的回复
static void ProcRequest(Exchange *exchange, ServiceImpl *serviceImpl)
{
//参数检查
if (serviceImpl == NULL || exchange->type == MSG_ACK || exchange->type == MSG_DIRECT) {
return;
}
//处理消息,若featureID不为NULL,则调用指定feature的消息处理函数,若为NULL,则调用service的消息处理函数
DEFAULT_MessageHandle(serviceImpl, &(exchange->id), &(exchange->request));
if (exchange->type == MSG_CON) {
//发送响应
SAMGR_SendResponse(&exchange->request, &exchange->response);
}
}
处理MSG_ACK类型的消息
//当消息类型为MSG_ACK时,执行响应处理函数
static void ProcResponse(Exchange *exchange)
{
if (exchange->handler == NULL) {
return;
}
if (exchange->type != MSG_ACK) {
return;
}
//直接调用响应处理函数处理
exchange->handler(&exchange->request, &exchange->response);
}
处理MSG_DIRECT类型的消息
//当消息类型为MSG_DIRECT时,执行响应处理函数
static void ProcDirectRequest(Exchange *exchange)
{
if (exchange->handler == NULL) {
return;
}
if (exchange->type != MSG_DIRECT) {
return;
}
//直接调用响应处理函数处理
exchange->handler(&exchange->request, &exchange->response);
}
更新exchange对象所属的服务实例
//返回当前exchange对象对应的ServiceImpl
static ServiceImpl *CorrectServiceImpl(Exchange *exchange, ServiceImpl *serviceImpl)
{
if (exchange->type == MSG_ACK) {
//ack消息使用最后一个服务,不需要修改
return serviceImpl;
}
if (serviceImpl == NULL || serviceImpl->serviceId != exchange->id.serviceId) {
//根据serviceId获取新的serviceImpl
serviceImpl = SAMGR_GetServiceByID(exchange->id.serviceId);
}
if (serviceImpl == NULL) {
return NULL;
}
return serviceImpl;
}
获取当前线程的私有变量,存储的值是消息队列ID
//获取当前线程绑定的消息队列的ID
MQueueId SAMGR_GetCurrentQueueID()
{
//取出当前线程存储在g_localKey中的值,即当前线程对应的消息队列ID
return (MQueueId)THREAD_GetThreadLocal();
}
服务开始处理消息
//开始处理消息,更新ServiceImpl的消息处理数和时间戳,并更改状态为SVC_BUSY
static void BeginWork(ServiceImpl *service)
{
if (service == NULL || service->inited != SVC_IDLE) {//疑惑!若当前服务状态为繁忙,从这里return后,下面的消息记录和时间戳更新都不会执行,那么会导致实际处理的消息数大于记录的消息数
//service为NULL 或者service的状态不为闲置,则返回
return;
}
if (service->ops.step == BOOT_SYS_WAIT) {
WDT_Start(MSG_PROC_THRESHOLD);
}
//更新service所处理的消息数
service->ops.messages++;
//更新处理消息的时间戳
service->ops.timestamp = SAMGR_GetProcessTime();
//更新服务状态为繁忙,表示当前服务正在处理
service->inited = SVC_BUSY;
}
服务处理消息结束
//结束处理消息,判断处理消息的时间间隔是否超出阈值,若超出需增加异常数并记录日志。最后更新状态为SVC_IDLE
static void EndWork(ServiceImpl *service, const Exchange *exchange)
{
if (service == NULL || service->inited != SVC_BUSY) {
return;
}
if (service->ops.step == BOOT_SYS_WAIT) {
WDT_Stop();
}
//处理的最后一条消息的时间
uint32 lastTime = service->ops.timestamp;
//当前时间
service->ops.timestamp = (uint32)SAMGR_GetProcessTime();
//时间间隔
uint32 interval = GET_INTERVAL(lastTime, service->ops.timestamp);
if (interval > MSG_PROC_THRESHOLD) {
//消息超时
const char *name = service->service->GetName(service->service);
HILOG_INFO(HILOG_MODULE_SAMGR, "Message Timeout <service:%s, feature:%d, type:%d, reqId:%d, time:%ums>",
name, exchange->id.featureId, exchange->type, exchange->request.msgId, interval);
//异常情况+1
service->ops.abnormal++;
}
//更新service的状态为SVC_IDLE
service->inited = SVC_IDLE;
}
总是有很多小伙伴反馈说:OpenHarmony开发不知道学习哪些技术?不知道需要重点掌握哪些OpenHarmony开发知识点? 为了解决大家这些学习烦恼。在这准备了一份很实用的鸿蒙全栈开发学习路线与学习文档给大家用来跟着学习。
针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植……等)技术知识点。
OpenHarmony 开发环境搭建:https://gitcode.com/HarmonyOS_MN/733GH/overview
《OpenHarmony源码解析》
搭建开发环境
系统架构分析
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……