Samgr_lite——如何初始化服务?(大结局前篇)


在完结篇中我们讲述了函数SAMGR_Bootstrap在系统完成系统服务和APP服务的注册后将服务进行了初始化,里面调用的两个非常重要的函数:InitializeAllServices和InitCompleted,进行初始化服务的大部分功能由它们两个完成,所以不看不行,本篇文章先看其中一个InitializeAllServices

还是先把前面的系列文章链接附在这里供小伙伴阅读学习
SA框架下的基于Publish函数的广播机制(从广播机制切入Samgr)(前言)
Samgr_lite——如何注册一个服务?(以广播服务为例)(序章)
Samgr_lite——如何注册一个服务?(以广播服务为例)(正篇)
Samgr_lite——如何注册服务对应的feature?(续章)
Samgr_lite——重要结构体Vector的相关知识
Samgr_lite——如何初始化服务?(终章)

干货来袭!我们探索的思路采取从代码出发,层层抽丝剥茧看看里面究竟如何运作

InitializeAllServices

1. 整体解读

1.1 InitializeAllServices

首先我们从整体出发来看看InitializeAllServices都干了哪些工作
在这里插入图片描述
函数流程:主要是两个for循环
1.在第一个for循环中,利用VECTOR_At得到Vector中管理的服务serviceImpl
2.然后通过service实现的两个函数GetTaskConfig和GetName获得taskConfig和字符串服务名字
3.根据serviceImpl、taskConfig、serviceName调用AddTaskPool进行三类taskPool的创建
4.再调用InitializeSingleService对每个serviceImpl进行服务初始化
5.第二个for循环中,同样拿到service对应的serviceImpl和name
6.对于每一个serviceImpl调用SAMGR_StartTaskPool开启线程池和队列任务

这里需要注意一点:为什么要分为两个for循环来做呢?——从代码中我们可以看到第二次for循环在获取了互斥锁之后进行操作的——说明涉及到共享数据或者结构体的修改和读写,而上面的for循环并不需要,所以分成了两个for循环

1.2 InitializeAllServices流程图

同样给出InitializeAllServices的流程图供读者参考
在这里插入图片描述

1.3 重要结构体TaskConfig

这里我们看到一个新的结构体类型TaskConfig

struct TaskConfig {
    int16 level;//多服务共享任务的分类level 在enum SpecifyTag中有详细取值
    int16 priority;//任务优先级 在enum TaskPrioriy中有详细取值
    uint16 stackSize;//任务堆栈的大小
    uint16 queueSize;//任务队列的大小
    uint8 taskFlags;//任务标志 在enum taskType中有详细取值
};

typedef enum SpecifyTag {
    LEVEL_HIGH = 0,
    LEVEL_MIDDLE = 1,
    LEVEL_LOW = 2,
    LEVEL_CUSTOM_BEGIN,
} SpecifyTag;

//鸿蒙原本的注释就比较详细
typedef enum TaskPriority {
    /** Low-priority: (9, 15) */
    PRI_LOW = 9,
    /** Lower than the normal priority: [16, 23) */
    PRI_BELOW_NORMAL = 16,
    /** Normal priority: [24, 31). The log service is available. */
    PRI_NORMAL = 24,
    /** Higher than the normal priority: [32, 39). The communication service is available. */
    PRI_ABOVE_NORMAL = 32,
    /** Upper limit of the priority */
    PRI_BUTT = 39,
} TaskPriority;

//任务类型——也就是在AddTaskPool中出现的三类taskPool
typedef enum TaskType {
    /** Tasks shared based on their priority by services */
    SHARED_TASK = 0,
    /** Task exclusively occupied by a service */
    SINGLE_TASK = 1,
    /** A specified task shared by multiple services */
    SPECIFIED_TASK = 2,
    /** No task for the service. Generally, this situation does not occur. */
    NO_TASK = 0xFF,
} TaskType;

1.4 重要结构体TaskPool

在这里插入图片描述

在后面讲解AddTaskPool中会对两个结构体进行解读
所以对于初始化的解读就自然落在了下面三个重要函数身上

2. 三个重要函数

2.1 AddTaskPool

先贴代码注释:

/*
函数功能:三类TaskPool的创建
函数参数:service:taskPool对应的服务 cfg:taskPool的参数设置 name:服务的字符串名称
函数返回:void
*/
static void AddTaskPool(ServiceImpl *service, TaskConfig *cfg, const char *name)
{
    if (service->taskPool != NULL) {
        return;
    }

    if (cfg->priority < PRI_LOW || cfg->priority >= PRI_BUTT) {
        HILOG_ERROR(HILOG_MODULE_SAMGR, "The %s service pri(%d) is out of range!", name, cfg->priority);
        cfg->priority = PRI_LOW;
    }

    //三类taskPool的处理
    switch (cfg->taskFlags) {
        case SHARED_TASK: {
            int pos = (int)cfg->priority / PROPERTY_STEP;//PROPERTY_STEP:8
            SamgrLiteImpl *samgr = GetImplement();
            if (samgr->sharedPool[pos] == NULL) {
            	//{LEVEL_HIGH, (int16) ((pos) * 8 + 1), 0x800, 25, SHARED_TASK}
                TaskConfig shareCfg = DEFAULT_TASK_CFG(pos);
                //为服务创建相应的队列和TaskPool
                samgr->sharedPool[pos] = SAMGR_CreateFixedTaskPool(&shareCfg, name, DEFAULT_SIZE);
            }
            service->taskPool = samgr->sharedPool[pos];
            //用于检测taskPool中的ref是否为空或者超过最大值
            if (SAMGR_ReferenceTaskPool(service->taskPool) == NULL) {
                HILOG_ERROR(HILOG_MODULE_SAMGR, "shared task:%p pri:%d ref is full", service->taskPool, cfg->priority);
                samgr->sharedPool[pos] = NULL;
            }
        }
            break;

        case SPECIFIED_TASK:
            //根据传入的config寻找config一致的referenceTaskPool
            service->taskPool = GetSpecifiedTaskPool(cfg);
            if (service->taskPool != NULL) {
                break;
            }

        //每个service单独使用的taskpool
        case SINGLE_TASK:
            service->taskPool = SAMGR_CreateFixedTaskPool(cfg, name, SINGLE_SIZE);
            break;
        default:
            break;
    }

    if (service->taskPool == NULL) {
        HILOG_ERROR(HILOG_MODULE_SAMGR, "Service<name:%s, flag:%d> create taskPool failed!", name, cfg->taskFlags);
    }
}

函数说明:
1.首先对于传入的config中的priority进行规范检测,不规范的进行日志输出并将其改为PRI_LOW(最低级的优先级)

2.switch-case语句,根据config中的taskFlags判断其类型并调用不同函数进行taskPool的创建

3.对于SHARED_TASK来说,它是由g_samgrImpl管理的shareTask,也就是说——对于用于该类型taskPool的服务来说,该服务的taskPool是在g_samgrImpl共享的。
在代码中我们也可以看到:当g_samgrImpl.sharedPool[pos]对应为NULL则调用DEFAULT_TASK_CFG创建一个高优先级的sharedTask类型的config,并调用SAMGR_CreateFixedTaskPool为服务创建相应的队列和taskPool。如果原本g_samgrImpl.sharedPool[pos]就存在了taskPool则直接service->taskPool = samgr->sharedPool[pos]建立共享池的关系。(另外这里的pos是通过cfg->priority / PROPERTY_STEP计算出来的,可取的值为1234,对应四种优先级的taskPool)

所以共享池的共享仍然是根据taskConfig中的不同优先级priority进行分配的,使用服务的共享池有利于提高OS的处理效率(函数SAMGR_CreateFixedTaskPool在下面会提到)

4.对于SPECIFIED_TASK来说,它是多个服务共享的一个任务池的类型。在代码中调用GetSpecifiedTaskPool,根据传入的config寻找referenceTaskPool,并将其赋给service->taskPool。对于如何找到相应的TaskPool则是调用函数GetSpecifiedTaskPool对所有的serviceImpl的taksPool的config和所给定的config进行memcmp和SAMGR_ReferenceTaskPool,最后让service.taskpool指向该config的taskPool

5.对于SINGLE_TASK,它是一个服务单独占用一个任务池。所以直接简单的调用SAMGR_CreateFixedTaskPool将新建的taskPool赋给service->taskPool即可

三类任务池的设置是为了对不同的服务进行更好的资源分配,设置优先级和level的目的也是如此

下面深入到几个函数源代码中瞧瞧其工作原理

2.1.1 SAMGR_CreateFixedTaskPool

在这里插入图片描述
逻辑比较简单,调用QUEUE_Create进行队列的创建;先调用SAMGR_Malloc进行taskPool空间分配,再依次给各个属性赋初值

这里注意一点:一个taskPool的队列只有一个,而对应的线程可以由很多;一个taskPool也可以对应多个serviceImpl——它的数量在taskPool->ref中记录(最大为15)

2.1.2 SAMGR_ReferenceTaskPool

在这里插入图片描述

2.1.3 GetSpecifiedTaskPool

在这里插入图片描述
主要通过for循环遍历所有的serviceImpl,将其taskPool.config与给定的config进行memcmp,一致则为需要的taskPool,返回该taskPool,然后taskPool.ref++表示关联的服务+1——通过该函数进行SPECIFIED_TASK类型的服务taskPool的添加


综上所述:AddTaskPool的实质是对于不同类型taskPool创建的不同处理

2.1.4 函数流程图

在这里插入图片描述

2.2 InitializeSingleService

先贴代码注解:
在这里插入图片描述
分两步走:如果传入的service没有对应的taskPool则调用DEFAULT_Initialize进行默认初始化处理;否则调用SAMGR_SendSharedDirectRequest传入HandleInitRequest交给对应的线程进行初始化处理 (处理的时候同样也调用了DEFAULT_Initialize)

下面是涉及的三个主要函数

2.2.1 DEFAULT_Initialize

在这里插入图片描述
这里也是分两步走:
第一步对serviceImpl调用Initialize和GetName进行初始化和获取服务名称,然后调用SAMGR_RegisterServiceApi进行默认的serviceApi注册(featureName:NULL);

第二步对于serviceimpl中绑定的所有feature后进行OnInitialize,然后获取其name传入SAMGR_RegisterServiceApi再次进行serviceImpl的注册

这里SAMGR_RegisterServiceApi的具体讲解由于篇幅原因在下下篇文章展开

2.2.2 SAMGR_SendSharedDirectRequest

在这里插入图片描述
在讲述广播机制的时候也提到过该函数,主要是实现对于exchange结构体的封装并调用SharedSend将exchange发送到指定队列中,处理的时候会根据里面封装的handler函数进行处理并返回结果

而这里的处理函数就是HandleInitRequest

2.2.3 HandleInitRequest

在这里插入图片描述
里面的核心也是DEFAULT_Initialize函数进行serviceApi的注册;

然后在serviceImpl->ops.timestamp中添加了初始化的时间戳;

最后调用了最后一篇要讲的InitCompleted来判断是否所有的服务都已经初始化完成

综上所述:InitializeSingleService的实质是完成了每个serviceImpl的serviceApi的注册

2.2.4 函数流程图

在这里插入图片描述


2.3 SAMGR_StartTaskPool

在完成了taskPool和serviceApi的注册后,来到最后一步——taskPool的启动
贴上代码注释:
在这里插入图片描述
函数的逻辑也比较清晰
1.首先是attr的创建
2.然后是调用THREAD_Create进行线程的创建(重要的任务入口函数TaskEntry)
3.再是在tasks中记录线程Id——便于以后的调用
4.最后就是根据size的大小,为一个taskPool创建多个thread,直到top>=size为止

具体task的运行机制大家可以自行阅读

函数流程图:
在这里插入图片描述

3. 总结

至此InitializeAllServices的所有代码基本分析完毕

它主要实现三件事来初始化所有的服务:
第一,三类taskPool的添加和创建,包括队列的创建;
第二,针对service和对应的feature进行serviceApi的注册;
第三,为创建的taskPool创建多个线程启动任务池。

这里给出整体的流程图供读者参考:
在这里插入图片描述

下一篇文章讲解InitCompleted

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国家一级假勤奋研究牲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值