竹笋

首页 » 问答 » 问答 » 鸿蒙学院鸿蒙内核源码分析特殊进程篇
TUhjnbcbe - 2023/7/14 21:17:00
早期如何治疗白癜风好 http://m.39.net/pf/a_4487596.html

三个进程

鸿蒙有三个特殊的进程,创建顺序如下:

2号进程,KProcess,为内核态根进程.启动过程中创建.

0号进程,KIdle为内核态第二个进程,它是通过KProcessfork而来的.这有点难理解.

1号进程,init,为用户态根进程.由任务SystemInit创建.

发现没有在图中看不到0号进程,在看完本篇之后请想想为什么?

家族式管理

进程(process)是家族式管理,总体分为两大家族,用户态家族和内核态家族.

用户态的进程是平民阶层,干着各行各业的活,权利有限,人数众多,活动范围有限.中南海肯定不能随便进出.这个阶层有个共同的老祖宗g_userInitProcess(1号进程).

内核态的进程是贵族阶层,管理平民阶层的,维持平民生活秩序的,拥有超级权限,人数不多.这个阶层老祖宗是g_kernelInitProcess(2号进程).

这两个阶层可以相互流动吗,有没有可以通过高考改变命运的机会?答案是:绝对不可能!!!龙生龙,凤生凤,老鼠生儿会打洞.从老祖宗创建的那一刻起就被刻在基因里了,抹不掉了.因为所有的进程都是由这两位老同志克隆(clone)来的,继承了这份基因.LosProcessCB有专门的标签来processMode区分这两个阶层.整个鸿蒙内核源码并没有提供改变命运机会的set函数.

2号进程KProcess

2号进程为内核态的老祖宗,也是内核创建的第一个进程,源码过程如下,省略了不相干的代码.

解读

main函数在系列篇中会单独讲,请留意自行翻看,它是在开机之初在SVC模式下创建的.

内核态老祖宗的名字叫KProcess,优先级为最高0级."KProcess"进程是长期活跃的,很多重要的任务都会跑在其之下.例如:

Swt_Task

oom_task

system_wq

tcpip_thread

SendToSer

SendToTelnet

eth_irq_task

TouchEventHandler

USB_GIANT_Task此处不细讲这些任务,在其他篇幅有介绍,但光看名字也能猜个八九,请自行翻看.

紧接着KProcess以CLONE_FILES的方式fork了一个名为"KIdle"的子进程.

内核态的所有进程都来自2号进程这位老同志,子子孙孙,代代相传,形成一颗家族树,和人类的传承所不同的是,它们往往是白发人送黑发人,子孙进程往往都是短命*,老祖宗最能活,子孙都死绝了它还在,有些收尸的工作要交给它干.

0号进程KIdle

0号进程是内核创建的第一个进程,在OsKernelInitProcess的末尾将2号进程设为当前进程后,紧接着就fork了0号进程.为什么一定要先设置当前进程,因为fork需要一个父进程,而此时系统处于启动阶段,并没有当前进程.是的,你没有看错.进程是操作系统为方便管理资源而衍生出来的概念,系统并不是非要进程,任务才能运行的.开机阶段就是啥都没有,默认跑在svc模式下,默认指定了入口地址reset_vector都是由硬件上电后规定的.进程,线程都是跑起来后慢慢赋予的含义,OsCurrProcessSet是从软件层面赋予了此为当前进程的这个概念.此处是内核设置的第一个当前进程.

解读

看过fork篇的可能发现了一个参数,KIdle被创建的方式和通过系统调用创建的方式不一样,一个用的是CLONE_FILES,一个是CLONE_SIGHAND具体的创建方式如下:

KIdle创建了一个名为Idle的任务,任务的入口函数为OsIdleTask,这是个空闲任务,啥也不干的.专门用来给cpu休息的,cpu空闲时就待在这个任务里等活干.

fork内核态进程和fork用户态进程有个地方会不一样,就是SP寄存器的值.fork用户态的进程一次调用两次返回(父子进程各一次),返回的位置一样(是因为拷贝了父进程陷入内核时的上下文).所以只能通过返回值来判断是父还是子返回.这个在fork篇中有详细的描述.请自行翻看.但fork内核态进程虽也有两次返回,但是返回的位置却不一样,子进程的返回位置是由内核指定的.例如:OsIdleTask就是入口函数.详见代码:

结论是创建0号进程中的OsCreateIdleProcess调用LOS_Fork后只会有一次返回.而且返回值为0,因为g_freeProcess中0号进程还没有被分配.详见代码,注意看最后的注释:

1号进程init

1号进程为用户态的老祖宗源码过程如下,省略了不相干的代码.

解读

从代码中可以看出用户态的老祖宗创建过程有点意思,首先它的源头和内核态老祖宗一样都在OsMain.

通过创建一个分离模式,优先级为10的系统任务SystemInit,来完成.任务的入口函数SystemInit()的实现由平台集成商来指定.本篇采用了hidv的实现.也就是说用户态祖宗的创建是在sysTask.uwStackSize=LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K栈中完成的.这个任务归属于内核进程KProcess.

用户态老祖宗的名字叫Init,优先级为28级.

用户态的每个进程有独立的虚拟进程空间vmSpace,拥有独立的内存映射表(L1,L2表),申请的内存需要重新映射,映射过程在内存系列篇中有详细的说明.

init创建了一个任务,任务的入口地址为__user_init_entry,由编译器指定.

用户态进程是指应有程序运行的进程,通过动态加载ELF文件的方式启动.具体加载流程系列篇有讲解,不细说.用户态进程运行在用户空间,但通过系统调用可以陷入内核空间.具体看这张图:

想了解更多精彩内容,快来

1
查看完整版本: 鸿蒙学院鸿蒙内核源码分析特殊进程篇