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; //改变状态值
}
以上为线程间通信和任务处理的过程,感谢阅读!