鸿蒙源码分析(六十四)

take_manager.c代码分析

线程通信代码解释

这里就是监控消息队列中是否有消息,如果有便将消息提取出来。否则就持续监控;
当消息提取出来还给查看消息的type是否为EXIT,如果是,则该进程可能要退出或者注销。

//这里也是监视进程变量,就是从消息队列中提取消息
static void *TaskEntry(void *argv)
{
    
    
    ServiceImpl *serviceImpl = NULL;
    //定义一个服务实例
    THREAD_SetThreadLocal(argv);

    //这里的argv可能会是个系统密钥,这个函数的目的就是用来实现获取和argv相关联的数据信息
    while (TRUE) {
    
    
        Exchange exchange;
        uint32 msgRcvRet = SAMGR_MsgRecv((MQueueId)argv, (uint8 *)&exchange, sizeof(Exchange));
        //接收exchange当中的信息,存入argv指向的数据结构
        if (msgRcvRet != EC_SUCCESS) {
    
    
            continue;
        }
        if (exchange.type == MSG_EXIT) {
    
    
            //type相当于一个消息的状态码
            SAMGR_FreeMsg(&exchange);
            break;
        }
        serviceImpl = CorrectServiceImpl(&exchange, serviceImpl);
        BeginWork(serviceImpl);
        ProcResponse(&exchange);
        ProcDirectRequest(&exchange);
        ProcRequest(&exchange, serviceImpl);
        EndWork(serviceImpl, &exchange);
        SAMGR_FreeMsg(&exchange);
    }
    QUEUE_Destroy((MQueueId)argv);
    //
    return NULL;
}

正常的消息将会有下面三个ProcXxx()中的一个来对消息进行处理,三个消息处理函数是互斥的,某个消息只能由三个中的一个来处理。

ProcResponse()只处理应答消息,实际上是直接由exchange内handler指向的函数来处理该应答内容。
在这里插入图片描述
ProcDirectRequest()只处理不需要回应的直接请求消息,实际上是直接由exchange内handler指向的函数来处理该消息。
在这里插入图片描述

ProcRequest()则处理其他类型的消息,由service/feature自己的MessageHandle来响应,如果需要返回应答消息,那就直接在发送一个Response消息就可以了。

static void ProcRequest(Exchange *exchange, ServiceImpl *serviceImpl)
{
    
    
    if (serviceImpl == NULL || exchange->type == MSG_ACK || exchange->type == MSG_DIRECT) {
    
    
        return;
    }
    //service指向的实例信息传入,然后根据request信息进行处理
    DEFAULT_MessageHandle(serviceImpl, &(exchange->id), &(exchange->request));
    if (exchange->type == MSG_CON) {
    
    
        //如果需要应答的话,就返回一个Response消息
        SAMGR_SendResponse(&exchange->request, &exchange->response);
    }
}

服务实例的相关函数

首先是服务实例的矫正,这里如果服务的type为ack,说明该服务是个可用服务,不用经过处理。若是参数中的服务id和exchange的id对应的服务id不一致,就更新一次。讲exchange中的id对应的服务指向serviceImpl。

//矫正服务实例信息
static ServiceImpl *CorrectServiceImpl(Exchange *exchange, ServiceImpl *serviceImpl)
{
    
    
    if (exchange->type == MSG_ACK) {
    
    
        // The ack message use the last service.
        return serviceImpl;
    }
    if (serviceImpl == NULL || serviceImpl->serviceId != exchange->id.serviceId) {
    
    
        serviceImpl = SAMGR_GetServiceByID(exchange->id.serviceId);
        //ecchange变量中的id信息中有服务id,这里通过id讲服务指向serviceImpl
    }
    if (serviceImpl == NULL) {
    
    
        return NULL;
    }
    return serviceImpl;
}

服务矫正之后,就可以正式的处理服务实例中的信息。beginwork函数基于WDT看门狗进行定时,开始工作后就将服务中的ops.message变量增加,这里可能是为了讲处理消息的个数统计出来,然后还要计算本次处理的时间写进timestamp变量,将状态值改为busy,表明进程正在工作中。这个时间值是用来计算处理过程的时间,应为这里只能获取一个原子时间,并不能得到一个时间段的长度,需要结束时候在计算一次差值才可以。

MQueueId SAMGR_GetCurrentQueueID()
{
    
    
    //获取当前的线程信息
    return (MQueueId)THREAD_GetThreadLocal();
}

static void BeginWork(ServiceImpl *service)
{
    
    
    if (service == NULL || service->inited != SVC_IDLE) {
    
    
        return;
    }
    if (service->ops.step == BOOT_SYS_WAIT) {
    
    
        WDT_Start(MSG_PROC_THRESHOLD);
        //定时器的复位,就是重新开始计时定时
    }
    service->ops.messages++;
    service->ops.timestamp = SAMGR_GetProcessTime();
    //获取当前进程的时间
    service->inited = SVC_BUSY;
}

endwork函数价格传给的服务进行处理,如果处理超时便将失败情况记录进log文件,记录失败次数。主要的原理就是计算人物的处理时间,通过一个宏定义函数GET_INTERVAL计算beginwork和endwork函数处理任务的时间差,用来和时间阈值进行比较是否有超时现象

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) {
    
    
        //可用时间如果大于阈值,也就是超时的意思,这时候我们将该情况计入log文件
        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);
        service->ops.abnormal++;
        //该变量是存储失败次数
    }
    service->inited = SVC_IDLE; //改变状态值
}

以上为线程间通信和任务处理的过程,感谢阅读!

猜你喜欢

转载自blog.csdn.net/m0_46976252/article/details/120892806