系统是怎样创建进程的?_解读HarmonyOS源码:HarmonyOS内核源码分析(进程管理篇)

本文基于OpenHarmony内核,分析了进程的基本概念,包括进程的状态迁移、进程控制块以及内核态和用户态进程的创建过程。内核态的KProcess进程在系统启动时创建,用户态进程由KProcess fork产生。文章还讨论了进程的优先级和调度机制,并提出了两个关于内存分配和进程池的问题。
摘要由CSDN通过智能技术生成

提示:本文基于开源鸿蒙内核分析,

官方源码【kernel_liteos_a

官方文档【docs

参考文档【Huawei LiteOS

官方源码【kernel_liteos_a】: 

https://gitee.com/openharmony/kernel_liteos_a

官方文档【docs】: 

https://gitee.com/openharmony/docs

参考文档【HuaweiLiteOS】:

https://support.huaweicloud.com/LiteOS/index.html 

基本概念

从系统的角度看,进程是资源管理单元。进程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它进程运行。

OpenHarmony内核的进程模块可以给用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。这样用户可以将更多的精力投入到业务功能的实现中。

OpenHarmony内核中的进程采用抢占式调度机制,支持时间片轮转调度方式和FIFO调度机制。

OpenHarmony内核的进程一共有32个优先级(0-31),用户进程可配置的优先级有22个(10-31),最高优先级为10,最低优先级为31。

高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。

每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离。

用户态根进程init由内核态创建,其它用户态进程均由init进程fork而来。

c2ea00b4affa9526f9b1404ec3ddae9d.png进程状态说明:

· 初始化(Init):该进程正在被创建。

· 就绪(Ready):该进程在就绪列表中,等待CPU调度。

· 运行(Running):该进程正在运行。

· 阻塞(Pend):该进程被阻塞挂起。本进程内所有的线程均被阻塞时,进程被阻塞挂起。

· 僵尸态(Zombies):该进程运行结束,等待父进程回收其控制块资源。

                                             ce33ba78a292e8b54a60ee2a74089880.png

(图 1 进程状态迁移示意图)

c2ea00b4affa9526f9b1404ec3ddae9d.png进程状态迁移说明:

· Init→Ready:

进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。

· Ready→Running:

进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则该进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存。

· Running→Pend:

进程内所有的线程均处于阻塞态时,进程在最后一个线程转为阻塞态时,同步进入阻塞态,然后发生进程切换。

· Pend→Ready / Pend→Running:

阻塞进程内的任意线程恢复就绪态时,进程被加入到就绪队列,同步转为就绪态,若此时发生进程切换,则进程状态由就绪态转为运行态。

· Ready→Pend:

进程内的最后一个就绪态线程处于阻塞态时,进程从就绪列表中删除,进程由就绪态转为阻塞态。

· Running→Ready:

进程由运行态转为就绪态的情况有以下两种:

1. 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。

2. 若进程的调度策略为SCHED_RR,且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。

· Running→Zombies:

当进程的主线程或所有线程运行结束后,进程由运行态转为僵尸态,等待父进程回收资源。

c2ea00b4affa9526f9b1404ec3ddae9d.png使用场景

进程创建后,用户只能操作自己进程空间的资源,无法操作其它进程的资源(共享资源除外)。用户态允许进程挂起,恢复,延时等操作,同时也可以设置用户态进程调度优先级和调度策略,获取进程调度优先级和调度策略。进程结束的时候,进程会主动释放持有的进程资源,但持有的进程pid资源需要父进程通过wait/waitpid或父进程退出时回收。

c2ea00b4affa9526f9b1404ec3ddae9d.png开始正式分析

我们先来做一个假设,好让大家有一个直观的感受。假设某地有一个10*40的400平米运动场馆,只供本地公司/组织/团体安排举办各种活动使用的,但因为生意太好,申请人太多了,每次都要排队,所以在场馆外面整了32条通道用来排队,而进程就是那些在场馆外32个队列里排队的人,那些队列就是进程的就绪队列。

请注意上面标注的红色的字 进程是资源管理单元 ,而非调度单元,调度单元是谁?是 Task/线程 ,看下官方对应状态的define

009022b7853e0a485fec82970dd797c2.png

一个进程从创建到消亡过程,在内核肯定是极其复杂的。一件这么复杂的事情肯定会有个复杂的结构体来承载,就是LosProcessCB(进程控制块),代码很长但必须全部拿出来,长是长了点,忍忍吧!

54e8190bad9ff705f3717a4cd89f7c87.png f2f5cc690c1ac77e53f3c48e348800bf.png eb7065b28f446aa716eac87cb5bde475.png 40ddfd3899ad1f3e43c9654e870431a7.png e0f08f483568adf9616bd6fdcbb0363c.png cfcddae742109e00c6e75bb7d54465d1.png

进程的模式有两种,内核态和用户态,能想到main函数中肯定会创建一个内核态的最高优先级进程,他就是 KProcess

调用过程如下

4e9a79e3baefd1588df24b04d5fe1eee.png

通过task命令查看任务运行状态,可以看到 KProcess 进程 ,看名字就知道是一个内核进程,在系统启动时创建,图中可以看到 KProcess 的task运行情况,从表里可以看到KProcess内有 10几个task

53a1a1a77218013685086208c642b31c.png

进程初始化

adbbb5d1e5dc13cc08655dfd3e9bb3d1.png

以上是.c 中的所有全部变量。注释是笔者添加的。

KProcess也在进程当中,也需要接受调度排队,但他们的优先级是最高的0级,他们进场后需完成场馆的准备工作,再开门做生意。如果需要多个,那该怎么办呢?答案就是通过fork,简单说就是复制一个,复制的前提是需要有一个,鸿蒙里就是KProcess,其他都是通过它fork的。那用户怎么来的呢?就是真正的进程,先创建一个,其他就是原来的fork来的。

还是直接看代码吧

19afb280c0a27e251c7eba8660b03f69.png 84a94dbb19422bd4c059f582781308ac.png e0104d750a3272878408be772b2c8a57.png

代码已经很清楚,创建了一个进程池,默认64个进程,也就是不改

宏LOSCFG_BASE_CORE_PROCESS_LIMIT的情况下 系统最多是64个进程,但有两个进程先被占用,用户态和内核态各一个,他们是后续创建进程的爹,所以最多留给外面的只有 62个进程可创建,代码的最后两个爸爸的task阻塞链表也被清空了。

创建内核态Kprocess的过程

创建核心态进程,也就是线程池中的 [2] 号进程,task 命令中 Kprocess PID = 2, 参数是 内核态和 最高优先级 0

fd91f0d5c00bf30c48674a9e8b1e48ed.png

 代码的把kprocess 设为当前进程,并且fork了一个 KIdle(内核态的空闲进程)

be844b046b88d3e544def2bad3208ac5.png 929903da3a8fc69bc6cfb2b6a03c57b1.png 66456aebced69018fb79d0d4e6527306.png

以上是内核态进程的初始化过程

创建用户态进程的过程是怎样的?

看代码

5efbe301797efa0f4809b678537b6bc3.png 5e7125f77ba652f6f75ff3be9f56e281.png 8420b36e217ceb19a4f42e20acaca4f2.png 3755d34c64277276c37816c16b55ec93.png 06e72fb02402eaaa9378ebe12322c56b.png 3623d01968bac733173494e64b2a9c4d.png

发现用户态init 和 创建的过程类似 内核态,并且用户态爸爸进程的优先级是 28,好低啊。

KProcess和真正进程的工作环境是不一样的,如果说真正进程是上面假设说的排队进场等待表演的人,那么KProcess就是场外驻守的工作人员,以上代码相当于划界限,真正进程只能在表演的场地活动,这个场地就是用户空间,内存就是整个场地,但工作人员并没有限制,它是可以全场活动的。

留下两个小问题请大家思考

 OsUserInitProcess里有些关于内存的代码,源码中找不到值,比如:

19740aae02de7ff5a071bc37e7a6b7fe.png

为什么会这样?另外两个爸爸对应的PID是 1和2,那进程池里的0号进程去哪里了?

END

60d3d5209df059e2a2e99691e980b9e2.png● 扫码关注欢迎留言投稿●

905171c22e293507a0b8031462c1db3e.gif

●近距离接触:HarmonyOS 2.0

●官宣!HarmonyOS 2.0来了

●OpenHarmony开源项目满月,TA到底怎么样?

●第一个HarmonyOS “Hello  World”运行及代码解析?

●HarmonyOS系统中的JS开发框架

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值