实验六:分析Linux内核创建一个新进程的过程

作者:王朝宪  《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

进程

1.进程即处于执行期的程序,并不局限于一个可执行的代码,是处于执行期程序以及其相关资源的总称。

2.Linux系统中,对于进程和线程并没有明显的区分,线程是一种特殊的进程。

3.Linux系统中,常用fork()进程创建子进程。调用fork()进程的成之为其子进程的父进程。

4.fork()继承实际上由clone()系统调用实现。最后通过exit()退出执行。

操作系统三大功能:

  • 进程管理
  • 内存管理
  • 文件系统

任务描述符及任务结构

1.进程描述符(PID),是每一个进程的唯一标识值

2.PID中state描述了进程当前的状态,每个进程都必然处于下列五中状态中的一种。

  TASK_RUNNING(可运行):标识该进程正在运行或等待运行,这是进程在用户空间执行的唯一可能状态。

  TASK_INTERRUPTLBLE:(可中断):进程在睡眠,等待某种条件的达成,等待被唤醒。

  TASK_UNINTERRUPTLBLR:(不可中断)

  _TASK_TRACED:被其他进程跟踪的进程

  _TASK_STOPPED:停止执行进程

进程创建

1.Linux将进程创建拆分为两个单独函数:fork()与exec(),前者拷贝当前进程创建子进程,后者负责读取可执行文件并将其载入地址空间开始运行。

2.Linux的fork()函数具有写时拷贝功能,只有在需要时,数据才会被复制。

3.fork()

  fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

1)在父进程中,fork返回新创建子进程的进程ID;
     2)在子进程中,fork返回0;
     3)如果出现错误,fork返回一个负值;

线程在Linux中实现

1.线程的创建和进程创建类似,但是在调用clone()时候需要传递一些参数标志来指明需要共享的资源。

2.传递的参数决定了新创建进程的行为方式和父子进程之间的共享种类。

3.内核线程与普通线程的区别在于:内核线程没有独立的地址空间,仅在内核空间运行。内核线程只能由其他内核线程创建,其祖先为kthreadd

Task running表示可以运行。是否在运行取决于他是否取得了内核的控制权

gdb跟踪分析一个fork系统调用内核处理函数sys_clone

启动menuos

cd LinuxKernel

rm menu -rf

git clone https://github.com/mengning/menu.git

cd menu

mv test_fork.c test.c

make rootfs


gdb调试fork命令

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
gdb
file linux-3.18.6/vmlinux
target remote:1234



总结:

Linux通过复制父进程来创建一个新进程,通过调用do_ fork来实现并为每个新创建的进程动态地分配一个task_ struct结构。

1. 新进程的开始

从ret_from_fork处开始执行
  • dup_task_struct中为其分配了新的堆栈
  • copy_process中调用了sched_fork,将其置为TASK_RUNNING
  • copy_thread中将父进程的寄存器上下文复制给子进程,这是非常关键的一步,这里保证了父子进程的堆栈信息是一致的。
  • ret_from_fork的地址设置为eip寄存器的值,这是子进程的第一条指令。

2. 执行起点与内核堆栈保证一致

  • 在设置子进程的ip之前:

    *childregs = *current_ pt_ regs();
  • 将父进程的regs参数赋值到子进程的内核堆栈,*childregs的类型为pt_regs,其中存放了SAVE ALL中压入栈的参数。

3.大致框架

  • 复制一个PCB——task_struct

    p = dup_task_struct(current);//复制进程的PCB
    
    int __weak arch_dup_task_struct(struct task_struct *dst,struct task_struct *src)
    {
    *dst = *src;//通过赋值实现复制
    return 0;
    }
  • 给新进程分配一个新的内核堆栈

    ti = alloc_thread_info_node(tsk, node);
    tsk->stack = ti;
    setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈
  • 修改复制过来的进程数据,比如pid、进程链表等(见copy_process内部)。

    /*copy_thread in copy_process*/
    /*拷贝内核堆栈数据和指定新进程的第一条指令地址*/
    *childregs = *current_pt_regs(); //复制内核堆栈,只复制了SAVE_ALL相关的部分
    childregs->ax = 0; //子进程的fork返回0的原因 p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
    p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址

实验 六:分析linux内核创建一个新进程的过程的更多相关文章

  1. 第六周分析Linux内核创建一个新进程的过程

    潘恒 原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 task_struct结构: ...

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

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

  3. linux内核分析作业6:分析Linux内核创建一个新进程的过程

    task_struct结构: struct task_struct {   volatile long state;进程状态  void *stack; 堆栈  pid_t pid; 进程标识符  u ...

  4. Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程

    Linux内核分析第六周学习笔记--分析Linux内核创建一个新进程的过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

  5. 作业六:分析Linux内核创建一个新进程的过程

    分析Linux内核创建一个新进程的过程 进程描述符PCB----task_struct数据结构 操作系统:1.进程管理 2.内存管理 3 文件系统 一.新进程如何创建和修改task_struct数据结 ...

  6. 《Linux内核--分析Linux内核创建一个新进程的过程 》 20135311傅冬菁

    20135311傅冬菁 分析Linux内核创建一个新进程的过程 一.学习内容 进程控制块——PCB  task_struct数据结构 PCB task_struct中包含: 进程状态.进程打开的文件. ...

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

    作者:江军 ID:fuchen1994 实验题目:分析Linux内核创建一个新进程的过程 阅读理解task_struct数据结构http://codelab.shiyanlou.com/xref/li ...

  8. 实验六:分析Linux内核创建一个新进程的过程

    原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 题目自拟,内容围绕对Linu ...

  9. 第六周——分析Linux内核创建一个新进程的过程

    "万子恵 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 &q ...

随机推荐

  1. css常见的概念

    padding-top:10px;是指容器内的内容距离容器的顶部有10个像素,是包含在容器内的: margin-top:10px;是指容器本身的顶部距离其他容器有10个像素,不包含在容器内: top: ...

  2. 页面元素固定在页面底部的纯css代码(兼容IE6)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. Linux-centos安装node、nginx小记

    一.安装node 1.进入/usr目录,新建toos目录 cd /usr && mkdir tools && cd tools 2.wget命令下载对应版本的node包 ...

  4. world转html在线编辑器

    轻量富文本编辑器插件:http://fex.baidu.com/ueditor/ http://ueditor.baidu.com/website/onlinedemo.html

  5. WebAPI项目中使用SwaggerUI

    1.创建webapi项目解决方案 2.引入Swagger组件 在项目引用中可以看到swagger的引用 3.webapi 项目右键属性->生成-> 勾选XML文档文件,然后将XML文件保存 ...

  6. MyBatis实战之配置

    MyBatis最重要的配置也就两个,一个是mybatis-config.xml,又称MyBatis的全局配置,另一个就是XXXDao.xml或XXXMapper.xml映射配置. mybatis-co ...

  7. shiro实战系列(六)之Authorization(授权)

    授权,又称作为访问控制,是对资源的访问管理的过程.换句话说,控制谁有权限在应用程序中做什么. 授权检查的例子是:该用户是否被允许访问这个网页,编辑此数据,查看此按钮,或打印到这台打印机?这些都是 决定 ...

  8. Kubernetes1.91(K8s)安装部署过程(五)--安装flannel网络插件

    node节点需要安装flannel网络插件才能保证所有的pod在一个局域网内通信,直接使用yum安装即可,版本是0.7.1. 1.安装flannel插件: 注意是2个node节点都需要安装,都需要修改 ...

  9. day61

    Vue 八.重要指令 v-bind <!-- 值a --> <div v-bind:class='"a"'></div> <!-- 变量a ...

  10. jqgrid 让隐藏的列在编辑状态时出现且可编辑

    有时,我们需要隐藏一个列数据,但在启动编辑时又能够被编辑. 1.设置列为编辑:editable: true 2.设置 editrules属性值为: edithidden: true colModel: ...