Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >OpenHarmony 轻内核A核源码分析系列七 进程管理 (2)

OpenHarmony 轻内核A核源码分析系列七 进程管理 (2)

原创
作者头像
小帅聊鸿蒙
发布于 2025-06-06 12:27:44
发布于 2025-06-06 12:27:44
640
举报
文章被收录于专栏:鸿蒙开发笔记鸿蒙开发笔记

本文先熟悉下进程管理的文件kernel\base\core\los_process.c中的内部接口,读读代码,做些记录。

1、LiteOS-A内核进程全局变量

⑴是进程池,存放各个进程控制块LosProcessCB的信息。⑵处开始的g_freeProcess是空闲进程链表,挂载各个空闲进程控制块;g_processRecycleList是待回收进程控制块链表,挂载各个等待回收的进程控制块。⑶处开始的g_userInitProcess是用户根进程的进程号,数值固定为1.,g_kernelInitProcess是内核进程,内核进程的进程号固定为2,g_kernelIdleProcess是内核空闲进程,进程号固定为0。⑷处开始的g_processMaxNum表示为配置的进程的最大数目,g_processGroup维护进程组信息,所有的进程组都会挂载这个全局进程组链表节点g_processGroup->groupList上。

代码语言:shell
AI代码解释
复制
⑴  LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL;
⑵  LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;
    LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecycleList;
⑶  LITE_OS_SEC_BSS UINT32 g_userInitProcess = OS_INVALID_VALUE;
    LITE_OS_SEC_BSS UINT32 g_kernelInitProcess = OS_INVALID_VALUE;
    LITE_OS_SEC_BSS UINT32 g_kernelIdleProcess = OS_INVALID_VALUE;
⑷  LITE_OS_SEC_BSS UINT32 g_processMaxNum;
    LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL;

2. 涉及空闲进程链表内部操作

空闲进程块链接操作涉及初始化OsProcessInit、插入空闲链接OsInsertPCBToFreeList、从链表获取空闲进程块OsGetFreePCB。我们先看下OsInsertPCBToFreeList和OsGetFreePCB。初始化链表在初始化进程时再看。

2.1 OsInsertPCBToFreeList

OsInsertPCBToFreeList函数会进程控制块插入到空闲进程块链表。函数比较简单,把进程结构体块清空,然后放入进程块链表。有个有意思的细节需要了解下。⑴处记录下进程号,然后把进程块置空。⑵处又把进程号设置给进程块结构体,进程号数量是固定的。⑶处开始设置进程为未使用状态,更新定时器编号未无效值,然后插入到空闲进程块链表。

代码语言:shell
AI代码解释
复制
    STATIC INLINE VOID OsInsertPCBToFreeList(LosProcessCB *processCB)
    {
⑴      UINT32 pid = processCB->processID;
        (VOID)memset_s(processCB, sizeof(LosProcessCB), 0, sizeof(LosProcessCB));
⑵      processCB->processID = pid;
⑶      processCB->processStatus = OS_PROCESS_FLAG_UNUSED;
        processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID;
        LOS_ListTailInsert(&g_freeProcess, &processCB->pendList);
    }

2.2 OsGetFreePCB

OsGetFreePCB函数用于从空闲进程链表中获取进程块,该函数只有在开启LOSCFG_KERNEL_VM的时候才生效。⑴处当空闲进程链表为空时,返回NULL。⑵处获取空闲进程块指针,然后虫空闲进程块链表中删除。

代码语言:shell
AI代码解释
复制
STATIC LosProcessCB *OsGetFreePCB(VOID)
{
    LosProcessCB *processCB = NULL;
    UINT32 intSave;

    SCHEDULER_LOCK(intSave);if (LOS_ListEmpty(&g_freeProcess)) {
        SCHEDULER_UNLOCK(intSave);
        PRINT_ERR("No idle PCB in the system!\n");
        return NULL;
    }

⑵  processCB = OS_PCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_freeProcess));
    LOS_ListDelete(&processCB->pendList);
    SCHEDULER_UNLOCK(intSave);

    return processCB;
}

3. 涉及进程和线程的内部操作

该类操作包含把线程从进程中删除OsDeleteTaskFromProcess,还包括把线程包含进进程OsProcessAddNewTask。

3.1 OsDeleteTaskFromProcess

OsDeleteTaskFromProcess函数用于从进程中删除一个线程。⑴处可以看出每个线程/任务控制块都维护进程号,根据进程号可以获取进程控制块。每个线程控制块通过自己的成员变量threadList挂载到进程的线程链表上。⑵处从进程的线程链表上删除,然后把进程的线程数减去1。

⑶处把任务控制块插入到待回收链表上。

代码语言:shell
AI代码解释
复制
    VOID OsDeleteTaskFromProcess(LosTaskCB *taskCB)
    {
⑴      LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);

⑵      LOS_ListDelete(&taskCB->threadList);
        processCB->threadNumber--;
⑶      OsTaskInsertToRecycleList(taskCB);
    }

3.2 OsProcessAddNewTask

函数OsProcessAddNewTask把线程关联到进程上,需要两个参数,分别进程号和线程控制块。需要注意返回值,返回值表示,关联新线程之前的,进程的线程数量。⑴处获取进程块,⑵处把线程块关联的进程号设置为参数中输入的进程号,然后把线程控制块挂载到进程的线程链表上。可以看出,线程块的threadList用于挂载到进程的线程链表,进程块的threadSiblingList节点用于挂载本进程下的各种线程。⑶处如果是用户态进程,标记线程的状态为用户态线程。⑷如果进程的线程数目大于0,线程的基础优先级basePrio设置为和进程的主线程的优先级一样,否则设置为最大优先级。⑸如果是内核进程,线程的基础优先级设置为当前线程的优先级。⑹处如果开启了虚拟内存,设置线程的MMU结构体信息为进程虚拟地址空间中维护的MMU。⑺处如果进程的线程数为0,则把线程设置为进程的主线程。然后把进程的线程数加1。⑻处获得进程已有的线程数量,然后把进程的线程数量增加1。然后返回进程的关联新线程之前的线程数量。

代码语言:shell
AI代码解释
复制
    UINT32 OsProcessAddNewTask(UINT32 pid, LosTaskCB *taskCB)
    {
        UINT32 intSave;
        UINT16 numCount;
⑴      LosProcessCB *processCB = OS_PCB_FROM_PID(pid);

        SCHEDULER_LOCK(intSave);
⑵      taskCB->processID = pid;
        LOS_ListTailInsert(&(processCB->threadSiblingList), &(taskCB->threadList));if (OsProcessIsUserMode(processCB)) {
            taskCB->taskStatus |= OS_TASK_FLAG_USER_MODE;if (processCB->threadNumber > 0) {
                taskCB->basePrio = OS_TCB_FROM_TID(processCB->threadGroupID)->basePrio;
            } else {
                taskCB->basePrio = OS_USER_PROCESS_PRIORITY_HIGHEST;
            }
        } else {
⑸           taskCB->basePrio = OsCurrTaskGet()->basePrio;
        }

    #ifdef LOSCFG_KERNEL_VM
⑹      taskCB->archMmu = (UINTPTR)&processCB->vmSpace->archMmu;
    #endif
        if (!processCB->threadNumber) {
⑺          processCB->threadGroupID = taskCB->taskID;
        }
        processCB->threadNumber++;

⑻      numCount = processCB->threadCount;
        processCB->threadCount++;
        SCHEDULER_UNLOCK(intSave);
        return numCount;
    }
DD一下:欢迎大家关注工粽号<程序猿百晓生>,可以了解到以下知识点。
代码语言:erlang
AI代码解释
复制
`欢迎大家关注工粽号<程序猿百晓生>,可以了解到以下知识点。`
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案) 
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.OpenHarmonyUboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......

4、涉及进程组的内部操作

涉及进程组的内部操作包含进程组的创建OsCreateProcessGroup、进程组的退出OsExitProcessGroup、查找进程组OsExitProcessGroup。

4.1 OsCreateProcessGroup

OsCreateProcessGroup函数用于根据进程号创建进程组,返回值为创建的进程组指针。进程组是动态创建的,⑴处为进程组控制块申请动态内存。⑵处进程组的groupId即为创建进程组的进程号,接着初始化进程组的两个链表。⑶处获取进程控制块,然后执行⑷把进程挂载到进程组的processList进程链表上,使用的挂载点为进程控制块的subordinateGroupList链表节点,所以看到这个成员变量,要想起来是在同一个进程组的各个进程的链接关系。然后更新进程的进程组信息,并更新进程状态为进程组leader。⑸处如果存在全局进程组,则把创建的进程组挂载到全局进程组变量上。

代码语言:shell
AI代码解释
复制
    STATIC ProcessGroup *OsCreateProcessGroup(UINT32 pid)
    {
        LosProcessCB *processCB = NULL;
⑴      ProcessGroup *group = LOS_MemAlloc(m_aucSysMem1, sizeof(ProcessGroup));
        if (group == NULL) {
            return NULL;
        }

⑵      group->groupID = pid;
        LOS_ListInit(&group->processList);
        LOS_ListInit(&group->exitProcessList);

⑶      processCB = OS_PCB_FROM_PID(pid);
⑷      LOS_ListTailInsert(&group->processList, &processCB->subordinateGroupList);
        processCB->group = group;
        processCB->processStatus |= OS_PROCESS_FLAG_GROUP_LEADER;if (g_processGroup != NULL) {
            LOS_ListTailInsert(&g_processGroup->groupList, &group->groupList);
        }

        return group;
    }

4.2 OsExitProcessGroup

OsExitProcessGroup函数用于把一个进程退出进程组,第一个参数指定进程控制块,第二个为输出参数,记录进程所在的进程组。⑴根据进程获取所在的进程组,然后获取进程组的主进程,然后获取主进程的进程控制块。⑵处把进程从进程组里删除。⑶处表示如果进程组下面没有挂载进程,并且进程组下面也没有挂载退出的进程,则执行⑷把进程组从全局进程组链表上删除。然后,把进程组的主进程的状态设置为非主进程OS_PROCESS_FLAG_GROUP_LEADER。⑸处如果主进程未使用状态并且主进程非退出状态,则把主进程从阻塞链表上删除,然后插入到空闲空闲进程链表上。⑹处既然进程推出了进程组,需要更新该进程的所属进程组为NULL。

代码语言:shell
AI代码解释
复制
    STATIC VOID OsExitProcessGroup(LosProcessCB *processCB, ProcessGroup **group)
    {
⑴      LosProcessCB *groupProcessCB = OS_PCB_FROM_PID(processCB->group->groupID);

⑵      LOS_ListDelete(&processCB->subordinateGroupList);if (LOS_ListEmpty(&processCB->group->processList) && LOS_ListEmpty(&processCB->group->exitProcessList)) {
⑷          LOS_ListDelete(&processCB->group->groupList);
            groupProcessCB->processStatus &= ~OS_PROCESS_FLAG_GROUP_LEADER;
            *group = processCB->group;if (OsProcessIsUnused(groupProcessCB) && !(groupProcessCB->processStatus & OS_PROCESS_FLAG_EXIT)) {
                LOS_ListDelete(&groupProcessCB->pendList);
                OsInsertPCBToFreeList(groupProcessCB);
            }
        }

⑹      processCB->group = NULL;
    }

4.3 OsFindProcessGroup

OsFindProcessGroup函数用于根据进程组编号获取进程组指针。⑴如果等于全局进程组的编号,则反正全局进程组指针。⑵处遍历全局进程组下面的各个进程组,判断遍历到的进程组的编号是否等于传入的进程组编号,如果相等则返回。如果执行到⑶,表明没有查询到指定的进程组编号的进程组信息。

代码语言:shell
AI代码解释
复制
    STATIC ProcessGroup *OsFindProcessGroup(UINT32 gid)
    {
        ProcessGroup *group = NULL;if (g_processGroup->groupID == gid) {
            return g_processGroup;
        }

⑵      LOS_DL_LIST_FOR_EACH_ENTRY(group, &g_processGroup->groupList, ProcessGroup, groupList) {
            if (group->groupID == gid) {
                return group;
            }
        }

⑶      PRINT_INFO("%s is find group : %u failed!\n", __FUNCTION__, gid);
        return NULL;
    }

小结

本文介绍了进程管理的文件本文先熟悉下进程管理的文件kernel\base\core\los_process.c中的部分内部接口。

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力;
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识;
  • 想要获取更多完整鸿蒙最新学习知识点,可关注B站:码牛课堂;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OpenHarmony 轻内核A核源码分析系列七 进程管理 (3)
本文记录下进程相关的初始化函数,如OsSystemProcessCreate、OsProcessInit、OsProcessCreateInit、OsUserInitProcess、OsDeInitPCB、OsUserInitProcessStart等。
小帅聊鸿蒙
2025/06/08
660
OpenHarmony 轻内核A核源码分析系列七 进程管理 (1)
本文开始继续分析OpenHarmony LiteOS-A内核的源代码,接下来会分析进程和任务管理模块。本文中所涉及的源码,以OpenHarmony LiteOS-A内核为例。如果涉及开发板,则默认以hispark_taurus为例。
小帅聊鸿蒙
2025/06/06
1320
OpenHarmony 轻内核A核源码分析系列七 进程管理 (1)
鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源?
进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。
小帅聊鸿蒙
2025/03/06
1140
鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源?
OpenHarmony 内核源码分析(Fork篇) | 一次调用,两次返回
笔者第一次看到fork时,说是一次调用,两次返回,当时就懵圈了,多新鲜,真的很难理解.因为这足以颠覆了以往对函数的认知, 函数调用还能这么玩,父进程调用一次,父子进程各返回一次.而且只能通过返回值来判断是哪个进程的返回.所以一直有几个问题缠绕在脑海中.
小帅聊鸿蒙
2025/03/20
1040
OpenHarmony 内核源码分析(Fork篇) | 一次调用,两次返回
OpenHarmony 轻内核M核源码分析系列六 任务及任务调度(2)任务模块
任务是操作系统一个重要的概念,是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源,并独立于其它任务运行。鸿蒙轻内核的任务模块可以给用户提供多个任务,实现任务间的切换,帮助用户管理业务程序流程。本文我们来一起学习下任务模块的源代码,所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m 获取。
小帅聊鸿蒙
2025/05/21
980
OpenHarmony 内核源码分析(进程回收篇) | 进程关系链
进程是家族式管理的,父子关系,兄弟关系,朋友关系,子女关系,甚至陌生人关系(等待你消亡)在一个进程的生命周期中都会记录下来.用什么来记录呢?当然是内核最重要的胶水结构体LOS_DL_LIST,进程控制块(以下简称PCB)用了8个双向链表来记录进程家族的基因关系和运行时关系.如下:
小帅聊鸿蒙
2025/03/21
520
OpenHarmony 内核源码分析(特殊进程篇)
2号进程为内核态的老祖宗,是内核创建的首个进程,源码过程如下,省略了不相干的代码.
小帅聊鸿蒙
2025/03/21
880
OpenHarmony 内核源码分析(特殊进程篇)
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
鸿蒙内核代码中有两个源文件是关于队列的,一个是用于调度的队列,另一个是用于线程间通讯的IPC队列。
小帅聊鸿蒙
2025/03/07
780
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
OpenHarmony 内核源码分析(调度机制篇) | 任务是如何被调度执行的
鸿蒙的内核中 Task 和 线程 在广义上可以理解为是一个东西,但狭义上肯定会有区别,区别在于管理体系的不同,Task是调度层面的概念,线程是进程层面概念。比如 main() 函数中首个函数 OsSetMainTask(); 就是设置启动任务,但此时啥都还没开始呢,Kprocess 进程都没创建,怎么会有大家一般意义上所理解的线程呢。狭义上的后续有 鸿蒙内核源码分析(启动过程篇) 来说明。不知道大家有没有这种体会,学一个东西的过程中要接触很多新概念,尤其像 Java/android 的生态,概念贼多,很多同学都被绕在概念中出不来,痛苦不堪。那问题是为什么需要这么多的概念呢?
小帅聊鸿蒙
2025/03/07
1350
OpenHarmony 内核源码分析(调度机制篇) | 任务是如何被调度执行的
OpenHarmony 轻内核M核源码分析系列九 互斥锁Mutex
多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的临界资源,只能被独占使用。鸿蒙轻内核使用互斥锁来避免这种冲突,互斥锁是一种特殊的二值性信号量,用于实现对临界资源的独占式处理。另外,互斥锁可以解决信号量存在的优先级翻转问题。用互斥锁处理临界资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务如果想访问这个临界资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个临界资源,保证了临界资源操作的完整性。
小帅聊鸿蒙
2025/05/23
800
OpenHarmony 轻内核M核源码分析系列三 数据结构-任务排序链表
在鸿蒙轻内核源码分析系列一和系列二,我们分析了双向循环链表、优先级就绪队列的源码。本文会继续给读者介绍鸿蒙轻内核源码中重要的数据结构:任务排序链表TaskSortLinkAttr。鸿蒙轻内核的任务排序链表,用于任务延迟到期/超时唤醒等业务场景,是一个非常重要、非常基础的数据结构。本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例。
小帅聊鸿蒙
2025/05/20
860
OpenHarmony 轻内核M核源码分析系列三 数据结构-任务排序链表
OpenHarmony 轻内核A核源码分析系列三 物理内存(2)
当执行到这个函数时,说明空闲链表上的单个内存页节点的大小已经不能满足要求,超过了第9个链表上的内存页节点的大小了。⑴处计算需要申请的内存大小。⑵从最大的链表上进行遍历每一个内存页节点。⑶根据每个内存页的开始内存地址,计算需要的内存的结束地址,如果超过内存段的大小,则继续遍历下一个内存页节点。
小帅聊鸿蒙
2025/05/30
620
OpenHarmony 轻内核A核源码分析系列三 物理内存(2)
OpenHarmony 内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
本篇为快锁下篇,说清楚快锁在内核态的实现,解答以下问题,它们在上篇的末尾被提出来。
小帅聊鸿蒙
2025/04/02
790
OpenHarmony 内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
OpenHarmony 轻内核M核源码分析系列八 静态内存MemoryBox
内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。
小帅聊鸿蒙
2025/05/22
1000
OpenHarmony 轻内核M核源码分析系列八 静态内存MemoryBox
OpenHarmony内核源码分析(时钟任务篇)
时钟节拍由配置为中断触发模式的硬件定时器产生,当中断到来时,将调用一次:void OsTickHandler(void),通知操作系统已经过去一个系统时钟;不同硬件定时器中断实现都不同,
小帅聊鸿蒙
2025/03/06
1440
谁是鸿蒙内核最重要的结构体?
结构体够简单了吧,只有前后两个指向自己的指针,但恰恰是因为太简单,所以才太不简单. 就像氢原子一样,宇宙中无处不在,占比最高,原因是因为它最简单,最稳定!
小帅聊鸿蒙
2025/03/06
610
谁是鸿蒙内核最重要的结构体?
OpenHarmony内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的
内存一开始一张白纸,这些extern就是给它画大界线的,从哪到哪是属于什么段。这些值大小取决实际项目内存条的大小,不同的内存条,地址肯定会不一样,所以必须由外部提供,鸿蒙内核采用了Linux的段管理方式。结合上图对比以下的解释自行理解下位置。
小帅聊鸿蒙
2025/03/08
1270
OpenHarmony内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的
OpenHarmony内核源码分析(进程概念篇) | 进程在管理哪些资源
官方文档最重要的一句话是进程是资源管理单元,注意是管理资源的, 资源是什么? 内存,任务,文件,信号量等等都是资源.故事篇中对进程做了一个形象的比喻(导演),负责节目(任务)的演出,负责协调节目运行时所需的各种资源.让节目能高效顺利的完成.
小帅聊鸿蒙
2025/03/12
1160
OpenHarmony内核源码分析(任务调度篇) | 任务是内核调度的单元
从系统的角度看,线程是竞争系统资源的最小运行单元。线程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它线程运行。
小帅聊鸿蒙
2025/03/07
1220
OpenHarmony 轻内核M核源码分析系列十一(1) 信号量Semaphore
信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数。以同步为目的的信号量和以互斥为目的的信号量在使用上存在差异。本文通过分析鸿蒙轻内核信号量模块的源码,掌握信号量使用上的差异。
小帅聊鸿蒙
2025/05/23
430
推荐阅读
相关推荐
OpenHarmony 轻内核A核源码分析系列七 进程管理 (3)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档