分析Linux内核创建一个新进程的过程

task_struct结构体分析

	struct task_struct{
volatile long state; //进程的状态
unsigned long flags; //调用fork时候给出的进程号
long nice; //进程的基本时间片
unsigned long policy; //进程的调度策略
struct mm_struct *mm; //进程内存管理信息
struct list_head run_list; //指向运行队列的指针
unsigned long sleep_time; //进程的睡眠时间
struct task_struct *next_task, *prev_task; //用于将系统中所有的进程连接成一个双向循环链表
pid_t pid;//进程标识符,用来代表一个进程
pid_t pgrp;//进程组标识,表示进程所属的进程组
pid_t tty_old_pgrp;//进程控制终端所在的组标识
pid_t session;//进程的会话标识
pid_t tgid;
struct list_head thread_group; //线程链表
struct task_struct *pidhash_next;//用于将进程链入HASH表pidhash
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit; //供wait4()使用
struct completion *vfork_done; // 供vfork() 使用
unsigned long rt_priority;//实时优先级
struct fs_struct *fs; //文件系统信息
struct files_struct *files; //打开文件信息
}

do_fork()函数分析

  • 不管是clone、fork还是vfork系统调用,他们的实现函数sys_clone、sys_fork和sys_vfork都指向了位于/kernel/Fork.c中的do_fork函数,唯一的不同就是clone_flags的不同。所以我们重在分析do_fork函数
  • do_fork函数调用copy_process函数,然后让进程开始运行。
  • do_fork步骤:
    • 查找pidmap_array位图,为子进程分配新的PID
    • 检查父进程ptrace字段,若其不为0,而且紫禁城不是内核线程,则do_fork()函数就会设置CLONE_PTRACE标志
    • 调用函数copy_process(),从而将复制进程描述符。如果所有必要的资源都是可用的,则copy_process()返回刚创建的task_struct描述符的地址。copy_process的具体步骤:
    • 检查参数clone_flags所传递标志的一致性
    • 通过调用security_task_create(clone_flags)函数以及security_task_alloc(p)函数执行安全检查
    • 调用dup_task_struct(current)函数来为子进程获得进程描述符
      • dup_task_struct函数将当前进程所获取的thread_info结构复制给子进程的thread_info结构中。
      • 执行alloc_task_struct(),用分配器task_struct_cachep为新进程获取进程描述符,并将进程描述符的地址保存在tsk中。
      • 执行alloc_thread_info来获取一片空的内存空间,用来存放新进程的thread_info和内核堆栈,并将这些内存区域字段的地址存放在变量ti中。
      • 将current进程描述符的内容复制到tsk所指向的task_struct结构体之中,然后把ti赋给tsk->thread_info,让心建立的tsk指向的task_struct和orig指向父进程的task_struct中的每个值,即将父进程的所有内容都复制给新的进程之中。
      • 把current进程的thread_info描述符的内容复制给ti所指向的结构体之中,将tsk赋给ti->task
      • 返回新进程的进程描述符指针tsk
    • 设置子进程与进程状态相关的几个关键字段:
      • 把大内核锁计数器tsk->lock_depth初始化为-1。
    • 把tsk->did_exec字段初始化为0:它记录了进程发出的execve()系统调用的次数。
    • 通过copy_flags函数更新从父进程复制到tsk->flags字段中的一些标志:首先清除PF_SUPERPRIV标志,该标志表示进程是否使用了某种超级用户权限。然后设置PF_FORKNOEXEC标志,它表示子进程还没有发出execve()系统调用。
    • 将新进程的PID存入tsk_pid字段
    • 调用copy_semundo、copy_files、copy_fs、copy_sighand、copy_signal、copy_mm和copy_namespace来创建新的数据结构,并把父进程的相应数据结构的值复制到新数据结构中,除非clone_flags参数指出它们有不同的值。
    • 调用copy_thread(0, clone_flags, stack_start, stack_size, p, regs),用发出clone()系统调用时CPU寄存器的值来初始化子进程的内核栈。进程描述符的thread.esp字段初始化为子进程内核栈的基地址,汇编语言函数ret_from_fork()的地址存放在thread.eip字段中。
    • 调用sched_fork(p)完成对新进程调度程序数据结构的初始化。
    • 如果已经设置了CLONE_STOPPED标志,那么子进程的状态会被设置成了终止状态。在另一个进程把子进程状态恢复成TASK_RUNNING之前,一直保持该状态。
    • 如果没有设置ClONE_STOPPED标志,则调用wake_up_new_task函数来调节父进程与子进程的调用顺序。
    • 终止并返回子进程描述符指针。
  • 在do_fork()结束之后,在内存开始调用子进程的时候,将会继续完善子进程,即将子进程描述符thread字段的值装入各CPU寄存器之中。尤其需要注意的是,需要把thread.esp装入esp寄存器,把函数ret_from_fork()的地址装入eip寄存器中。

实验内容

  • 设置断点

  • 调用do_fork

  • 调用copy_process

  • 调用dup_task_struct

  • 细节步骤

总结

* dup_task_struct中为其分配了新的堆栈
* 调用了sched_fork,将其置为TASK_RUNNING
* copy_thread中将父进程的寄存器上下文复制给子进程,保证了父子进程的堆栈信息是一致的
* 将ret_from_fork的地址设置为eip寄存器的值
* 最终子进程从ret_from_fork开始执行。

池彬宁原创作品转载请注明出处 + 《linux内核分析》mooc课程http://mooc.study.163.com/course/ustc-1000029000 ”

Linux内核分析-创建新进程的过程的更多相关文章

  1. Linux内核分析— —创建新进程的过程

    分析Linux内核创建一个新进程的过程 实验过程 要求:使用gdb跟踪分析一个fork系统调用内核处理函数sys_clone ,验证对Linux系统创建一个新进程的理解,推荐在实验楼Linux虚拟机环 ...

  2. Linux内核分析 笔记六 进程的描述和进程的创建 ——by王玥

    一.知识点总结 (一)进程的描述 1.操作系统内核里有三大功能: 进程管理 内存管理 文件系统 2.进程描述符:task_struct 2.进程描述符——struct task_struct 1. p ...

  3. Linux内核分析 笔记八 进程的切换和系统的一般执行过程 ——by王玥

    一.进程切换的关键代码switch_to的分析 (一)进程调度与进程调度的时机分析 1.不同类型的进程有不同的调度需求 第一种分类: I/O-bound:频繁地进行I/O,花费很多的时间等待I/O操作 ...

  4. 分析Linux内核创建一个新进程的过程【转】

    转自:http://www.cnblogs.com/MarkWoo/p/4420588.html 前言说明 本篇为网易云课堂Linux内核分析课程的第六周作业,本次作业我们将具体来分析fork系统调用 ...

  5. 20135202闫佳歆--week6 分析Linux内核创建一个新进程的过程——实验及总结

    week 6 实验:分析Linux内核创建一个新进程的过程 1.使用gdb跟踪创建新进程的过程 准备工作: rm menu -rf git clone https://github.com/mengn ...

  6. 《Linux内核分析》第六周 进程的描述与创建

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK SIX(3 ...

  7. LINUX内核分析第六周学习总结——进程的描述和进程的创建

    LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  8. 20135239益西拉姆 Linux内核分析 进程的描述和进程的创建

    [益西拉姆 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] 第六周 进程的描述 ...

  9. 《Linux内核分析》第六周笔记 进程的描述和进程的创建

    进程的描述和进程的创建 一.进程的描述 1.进程描述符task_struct数据结构(一) 操作系统的三大功能:进程管理(核心).内存管理.文件系统. 进程控制块PCB——task_struct(进程 ...

随机推荐

  1. BeanFactory和ApplicationContext的简单介绍

    引言 Spring通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语音的反射功能实例化Bean并建立Bean之间的依赖关系.Spring的IoC容器在完成这些底层工作的基础上,还提供 ...

  2. Python数据分析实例操作

    import pandas as pd #导入pandas import matplotlib.pyplot as plt #导入matplotlib from pylab import * mpl. ...

  3. centos7下安装docker(6镜像总结)

    学了很长时间的镜像了,从镜像的分层,缓存的特性,到制作镜像:通过docker commint和docker build创建,再到制作dockerfile以及dockerfile中常用的参数FROM,M ...

  4. NOIP2018爆零退役滚粗记

    \(Day\ -1\) 非常的颓废 上午考了loli\(\ \ oi\)的最后一轮,\(mhr\)一个小时十五分钟怒切\(260\)分,吊打生爷 发现自己\(T2\)树的直径写怪了,不明觉厉 怕不是要 ...

  5. M100 (0)开发

    [SDCC 2015现场]大疆Paul Yang:多旋翼飞行器的未来就是机器人的未来 http://www.csdn.net/article/2015-11-19/2826268 开发官网 https ...

  6. 2、JUC--CAS算法

     CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问. CAS 是一种无锁的非阻塞算法的实现. C ...

  7. 20145203盖泽双《网络对抗技术》实践五:MSF基础应用

    20145203盖泽双<网络对抗技术>实践五:MSF基础应用 1.实践目标 掌握metasploit的基本应用方式,掌握常用的三种攻击方式的思路.下面是我自己做的时候用的四个套路. (1) ...

  8. 使用 ps、strace、lsof 进行 Linux 进程 trouble-shooting

      linux_observability_tools 介绍 在Linux 下进行进程的排错,有很多方法.比如,修改源代码,print出一些关键的信息,如果代码是Python 的话,可以使用trace ...

  9. Linux系统远程连接服务器命令行模式

    导读 对于很多新手来说,如何用Windows远程Linux操作系统,是个前进的大问题.如果这个问题前进不了,其他更别说了. Linux或Max OS X系统电脑,登录步骤为 1.打开ssh客户端 2. ...

  10. django_redis作为 session backend 使用配置

    Django 默认可以使用任何 cache backend 作为 session backend, 将 django-redis 作为 session 储存后端不用安装任何额外的 backend # ...