本篇文章为你们展示了怎样剖析Linux内核源码do_fork,内容简明简练而且容易理解,绝对能使你眼前一亮,通过这篇文章的详尽介绍希望你能有所收获。
我们都晓得进程是Linux内核中最为重要的一个具象概念,这么我们平常在fork一个进程时,该进程到底是如何形成的呢?
推送会探讨一下在进程创建过程中饰演着重要角色的do_fork函数。
内核怎样来具象一个进程
内核通过一个称作task_struct的结构体来具象一个进程,该结构体的定义(以内核2.6为例)在include/linux.sched.h中。
截取部份task_struct如下:
上述task_struct属性是我摘录出的部份其结构体中的属性,我们从中可以大致了解到标示一个进程的属性大致会有该用以表示该进程所处的状态,进程的标志,以及进程是否被其他进程跟踪,进程锁的深度,进程的优先级,进程的pid,进程的父亲,进程的儿子数组linux应用程序,进程所打开的文件描述符表linux内核4.4源码下载,进程所处的文件系统,进程的讯号。。。。等等一堆我们平常可能碰到的和进程相关的东西。
do_fork简单剖析
接触linuxC编程的人都晓得,创建一个进程我们须要调用fork函数,fork虽然又是调用了clone函数来实现的,而clone函数中最关键的函数就是do_fork函数。
在剖析do_fork前我们脑海中可以大致想像一下,进程到底是怎样被创建下来的,如果让你来创建一个进程你会咋么做?
我们可以这样去剖析,既然原先的进程被具象成一个task_struct,这么新进程也是一个task_struct只不过它上面的一些属性会不同与原先的task_struct,这么创建一个新进程所要做的工作就是形参一个与原先进程一样都的task_struct结构,之后之后将新进程的task_struct不同于原先task_struct的属性进行更改即可。
do_fork定义在kernel/fork.c文件中。
在剖析该函数之前我们先来剖析一下它的函数的各个参数。
参数如下:
1.clone_flags:该参数是此函数中最重要的一个参数,该值中的每位位都代表对子进程task_struct中的每种属性的设置;
2.stack_start:子进程用户态堆栈的开始地址;
3.regs:当系统发生系统调用时,需从用户态切换到内核态,此结构体拿来保存此时用户态进程中的通用寄存器中的值,并被储存在内核态堆栈中;
4.stack_size:目前未被使用,一般设为0;
5.parent_tidptr:父进程在用户态下pid的地址;
6.child_tidptr:子进程在用户态下pid的地址;
其中clone_flags的标志位宏定义如下:
举个简单的事例当我们的参数中设置了CLONE_VM这个宏,这么就以为这我们新创建的进程和其父进程要共享VM,当我们设置了CLONE_FILES时意味这母子进程之间共享打开的文件描述符。
do_fork开始执行后首先做的就是为子进程定义一个新的task_struct表针:
structtask_struct*p;
在出来会检测一些clone_flags所不容许的位组合,比如:
if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; }
上述中不容许同时既设置了CLONE_NEWUSER标志,还设置CLONE_THREAD标志,这样才会形成错误。
类似前面当一系列的安全检测完毕以后,copy_process函数就登场了,copy_process函数工作流程具体如下:
1)调用dup_task_struct函数为新的进程创建一个内核栈,thread_info结构和task_struct等,其实此时的值都是和父进程完全一样的
dup_task_struct函数定义如下:
2)检测并确保新创建该子进程后,当前用户所拥有的进程数没有超出给它分配的资源限制,代码如下:
3)子进程着手使自己与父进程区别开来,从父进程那承继过来的许多属性都要被清0或设置一个初始值,但task_struct中的大多数数据还是未被更改,部份代码如下:
4)给子进程分配一个CPU,代码如下:
sched_fork(p, clone_flags);
5)接着就是子进程拷贝父进程的一些资源,具体如下,调用copy_files函数拷贝父进程打开的文件描述符:
调用copy_fs承继父进程所属的文件系统。
调用copy_signal函数拷贝并设置新的signal_structlinux内核4.4源码下载,signal_struct包含了大量的进程运行的信息,调用copy_mm函数处理与新进程的显存问题。
调用copy_io函数拷贝父进程的I/O情况:
还有调用copy_namespaces和copy_thread等,这儿就不在赘言。
6)调用alloc_pid为新进程分配一个pid。
pid=alloc_pid(p->nsproxy->pid_ns);
7)copy_process做一些扫尾工作,并返回新进程的task_struct表针,此时再度回到了do_fork,新创建的子进程被唤起linux操作系统下载,并让其先投入运行。
总结
关于进程创建的源码理解,我觉得主要捉住俩点即可。***进程被内核具象成了啥?它的数据结构是咋样的(task_struct)这点我们必须有所认识,第二创建进程最主要的当然就是拷贝父进程的task_struct里的属性,而且关键点是拷贝什么,什么又是子进程和父进程所不同的,很简单我们只须要把松开进程创建函数里的clone_flags参数就可以晓得如何拷贝了。
上述内容就是怎样剖析Linux内核源码do_fork,大家学到知识或技能了吗?假如还想学到更多技能或则丰富自己的知识储备,欢迎关注亿速云行业资讯频道。