do_fork()函数流程分析

do_fork()实现

一、在分析do_fork()之前,我们需要对进程要有一定的认识,因为do_fork()是创建进程的。

进程四要素:

1、  有一段程序供其执行;

2、  有进程专用的系统堆栈空间,即内核栈;

3、  有进程控制块task_struct结构体;

4、  有独立的存储空间,专用的用户空间,即用于虚存管理的mm_struct结构、下属vm_area结构,以及相应的页面目录项和页面表,都从属于task_struct结构。

在include/linux/sched.h中定义了task_struct结构:PCB是进程存在和运行的唯一标识,在进程控制块task_struct结构中主要包含进程的状态、性质、资源和组织。

部分截取task_struct结构:

进程系统堆栈示意图:

二、Linux提供三个创建进程的系统调用,fork()、vfork()无参数的,clone()带参数的。

原型:

pid_t fork(void);

pid_t vfork(void);

int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);

区别:fork()是全部复制,父进程所有资源都通过数据结构的复制“遗传”给子进程;vfork()除了task_struct结构和系统空间堆栈以外的资源全部通过数据结构指针的复制“遗传”给子进程;而clone()则将资源有选择的复制给子进程,没有复制的数据结构则通过指针的复制让子进程共享。

由系统调用:

系统调用服务例程:

上图可得到:三种调用会进入同一个接口do_fork(),只是标志不同。

三、do_fork()实现流程:

先看do_fork()函数:

流程注解:

1、在do_fork()函数中首先创建一个task_struct结构体指针,再对传递给do_fork的flag参数进行处理和检查,看当前进程是否设置了跟踪标记ptrace。

2、然后进入了copy_process函数,实现将父进程的寄存器以及所有进程执行环境的相关部分复制给子进程。

在copy_process()函数中:首先对一些标志进行合法性检查,检查完之后调用dup_task_struct函数来为新进程创建一个内核栈、thread_info和task_struct,这里完全copy父进程的内容。

copy_process()函数流程图:

dup_task_struct函数:

注解:

调用alloc_task_struct_node()从系统高速缓存中分配task_struct空间;

调用alloc_thread_info_node()为新进程分配连续两个页面的空间,返回值指向thread_info的首地址,这是内核栈和thread_info的存放空间;

调用arch_dup_task_struct(tsk, orig)将父进程的task_struct复制给子进程的task_struct;

tsk->stack = ti;将子进程task_struct结构体的stack指针指向thread_info结构,这样便建立了task_struct与thread_info之间的联系了;

setup_thread_stack(tsk, orig);函数是将父进程的thread_info的内容完全复制到子进程的thread_info中,并在子进程中建立thread_info和task_struct之间的联系。

3、返回到copy_process()函数:

初始化task_struct结构中的各个成员了,主要涉及到拷贝clone_flags、初始化相关链表。调用sched_fork函数(Linux/kernel/sched/core.c)设置处理器的相关标记,并分配特定标号的处理器给该进程。其中的处理器相关标记包括:分配处理器标号、设置进程的优先级、设置与该进程调度相关的调度类等。

4、复制/共享进程的各个部分,某一部分是否父子进程共享主要由clone_flags中的相关标志位决定的。

注解:copy_process中包含的函数:copy_files()、copy_fs()、copy_sinhand()、copy_mm()

关于copy_files()、copy_fs()、copy_fs_struct()、copy_sinhand()、copy_mm()、dup_mmap()、copy_page_range()函数原型可以在源代码中找到。

copy_process()中copy_files()有条件的复制已打开文件的控制结构;copy_fs()共享或复制进程与文件系统的关系,主要通过copy_fs_struct()进行处理;copy_sighand()复制父进程对信号的处理;copy_mm()是对用户空间的继承,其中dup_mmap()复制vm_area_struct结构和页面映射表,copy_page_range()函数逐层处理页面目录项和页面表项。

5、设置各个ID、进程关系

在copy_process()中调用以上函数完成对task_struct的复制,接下来调用copy_thread()函数创建子进程系统堆栈,实际上是复制父进程的系统空间,即用父进程的内核栈内容更新子进程的内核栈。

子进程系统堆栈示意图:

6、  copy_process()函数成功执行之后返回do_fork()函数执行以下代码:

注解:调用get_task_pid()函数返回进程p的PID,然后对一些标志位进行处理,调用函数wake_up_new_task函数初始化调度器的一些基本参数,把该任务放入到就绪队列中等待调度器的调度,并设置该任务的运行状态为TASK_RUNNING。最后return进程的PID。

三个系统调用比较:

注解:

fork():fork()通过sys_fork()进入do_fork()时,其clone_flags为SIGCHILD,即所有标志位均为0,所以copy_files()、copy_fs()、copy_sighand()、copy_mm()全部执行。

vfork():vfork()通过sys_vfork()进入do_fork()时,其clone_flags为VFORK|CLONE_VM | SIGCHLD,所以执行copy_files()、copy_fs()、copy_sighand(),对于copy_mm(),由于标志位CLONE_VM为1,通过指针共享mm_struct。

clone():取决于调用时的参数。

经过上述过程,一个新的进程产生,关于进程的执行可以分析exec函数族。

报告只是简单分析了do_fork()大致实现流程,至于具体的实现可以阅读源码深入理解。

时间: 2024-10-10 05:40:31

do_fork()函数流程分析的相关文章

Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析

本篇博客旨在分析Android中广播相关的源码流程. 一.基础知识 广播(Broadcast)是一种Android组件间的通信方式. 从本质上来看,广播信息的载体是intent.在这种通信机制下,发送intent的对象就是广播发送方,接收intent的对象就是广播接收者. 在Android中,为广播接收者定义了一个单独的组件:BroadcastReceiver. 1 BroadcastReceiver的注册类型 在监听广播前,要将BroadcastReceiver注册到系统中. Broadcas

thttpd和cgilua安装与运行流程分析

安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/dragoncheng/article/details/5614559 thttpd配置文件: [email protected]:/usr/local/bin# cat /usr/local/thttpd/conf/ etc/  logs/ man/  sbin/ www/  [email protecte

u-boot启动流程分析(2)_板级(board)部分

转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global data介绍以及背后的思考 5. 前置的板级初始化操作 6. u-boot的relocation 7. 后置的板级初始化操作 1. 前言 书接上文(u-boot启动流程分析(1)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_i

Cocos2d-x3.3RC0的Android编译Activity启动流程分析

本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXV4aWt1b18x/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > watermark/2/text/aHR0cDov

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二)

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二) 1.通过mutate(put)操作,将单个put操作添加到缓冲操作中,这些缓冲操作其实就是Put的父类的一个List的集合.如下: private List<Row> writeAsyncBuffer = new LinkedList<>(); writeAsyncBuffer.add(m); 当writeAsyncBuffer满了之后或者是人为的调用backgroundFlushCommits操作促使缓冲池中的

基于linux与busybox的reboot命令流程分析

http://www.xuebuyuan.com/736763.html 基于Linux与Busybox的Reboot命令流程分析 *************************************************************************************************************************** 作者:EasyWave                                                

Solr4.8.0源码分析(5)之查询流程分析总述

Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilter的dofilter开始.dofilter包含了对http的各个请求的操作.Solr的查询方式有很多,比如q,fq等,本章只关注select和q.页面下发的查询请求如下:http://localhost:8080/solr/test/select?q=code%3A%E8%BE%BD*+AND+l

Android 7.0 ActivityManagerService(8) 进程管理相关流程分析(2)

前一篇博客进程管理相关流程分析(1)里, 我们介绍了AMS中updateLruProcessLocked函数相关的流程. updateLruProcessLocked只是按照进程中运行的组件,粗略地定义了不同进程的优先级. 实际上,Android根据进程的oom_adj进行了更加细致的进程分类, 而AMS中的updateOomAdjLocked函数,就是用于更新进程的oom_adj值. 本篇博客中,我们来看看AMS中updateOomAdjLocked相关的流程. 一.ProcessList.j

u-boot启动流程分析(1)_平台相关部分

转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—>cpu”框架,介绍u-boot中平台相关部分的启动流程.并通过对启动流程的简单分析,掌握u-boot移植的基本方法. 注1:本文所使用的u-boot版本,是2016/4/23从u-boot官网(git://git.denx.de/u-boot.git)导入的一个快照,具体可参考“https://github