张文俊 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

1、进程的描述

进程控制块PCB——task_struct

为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符(即task_struct)提供了内核所需了解的进程信息。

父子进程关系管理:

这是CPU状态,在进程上下文切换的过程中,起到关键作用:

2、进程的创建

进程的创建概览和fork一个进程的用户态代码

以fork一个子进程的代码为例:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int main(int argc, char * argv[])
  5. {
  6. int pid;
  7. /* fork another process */
  8. pid = fork();
  9. if (pid < 0)
  10. {
  11. /* error occurred */
  12. fprintf(stderr,"Fork Failed!");
  13. exit(-1);
  14. }
  15. else if (pid == 0)
  16. {
  17. /* child process */
  18. printf("This is Child Process!\n");
  19. }
  20. else
  21. {
  22. /* parent process  */
  23. printf("This is Parent Process!\n");
  24. /* parent will wait for the child to complete*/
  25. wait(NULL);
  26. printf("Child Complete!\n");
  27. }
  28. }

可用fork系统调用在父进程和子进程各返回一次。在fork之后,这段代码实际上就变成了两个进程。

理解进程创建过程复杂代码的方法

系统调用回顾:

创建一个新进程在内核中的执行过程

  • fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建;

  • Linux通过复制父进程来创建一个新进程,那么这就给我们理解这一个过程提供一个想象的框架:

    • 复制一个PCB——task_struct

      1. err = arch_dup_task_struct(tsk, orig);
    • 要给新进程分配一个新的内核堆栈

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

  • 从用户态的代码看fork();函数返回了两次,即在父子进程中各返回一次,父进程从系统调用中返回比较容易理解,子进程从系统调用中返回,那它在系统调用处理过程中的哪里开始执行的呢?

这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copy_thread in copy_process

  1. *childregs = *current_pt_regs(); //复制内核堆栈
  2. childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
  3. p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
  4. p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址

浏览进程创建过程相关的关键代码

以上为复制数据结构部分代码,dup_task_struct。这段代码相对简单,就是将src其中内容赋值给dst。

以上为alloc调用,它功能就是生成了两个页面。

重点还是看copy_thread的功能,pt_regs获取了pid指向的堆栈内信息,比如栈底等内容。

这是父进程对已有堆栈数据的copy,拷贝内核堆栈数据和指定新进程的第一条指令地址。

因为子进程的返回值为0,所以copy时还需要修改一下内核栈内压入的。

子进程是从哪里开始执行的?

子进程是从这个位置开始执行的,就是fork返回值被得到的时候。

对pt_regs内容进行查看,可以看到其中包含int指令和SAVE_ALL压到内核栈的内容。只复制了i32的相关内容。

从entry_32中,可以找到ret_from_fork的函数代码部分。

会跳到syscall_exit部分继续执行。正常返回到用户态。

使用gdb跟踪创建新进程的过程

如果用实验楼环境,首先需要rm menu -rf 删除原先menu 然后clone一份新的。

然后进入menu后,mv test_fork.c test.c,把test.c覆盖掉。

然后make rootfs,编译出来。

可以发现fork被进入到menu里。

然后使用gdb调试,使用-s -S。

然后设置断点:b sys_clone 和 b do_fork 和 b dup_task_struct 和 b copy_process 和 b copy_thread 和 b ret_from_fork

然后进行n单步调试。

可以看到子进程执行的起点。

3、总结

linux 系统创建进程都是用 fork() 系统调用创建子进程。

由 fork() 系统调用创建的新进程被称为子进程。

该函数被调用一次,但返回两次。

如果 fork()进程调用成功,两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程号。

"Linux内核分析"第六周实验报告的更多相关文章

  1. 《Linux内核分析》第二周学习报告

    <Linux内核分析>第二周学习报告 ——操作系统是如何工作的 姓名:王玮怡  学号:20135116 第一节 函数调用堆栈 一.三个法宝 二.深入理解函数调用堆栈 三.参数传递与局部变量 ...

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

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

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

    LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...

  4. linux内核分析第六周学习笔记

    LINUX内核分析第六周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...

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

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

  6. linux内核分析 第六周

    一.进程的描述 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. 1.进程控制块PCB--task_struct 进程状态 进程打开的文件 进程优先级信息 2. ...

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

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.进程的描述 ...

  8. 《Linux内核分析》第一周学习报告

    第一周:计算机是如何工作的 姓名:王玮怡  学号:20135116 第一节 存储程序计算机工作模型(冯诺依曼体系结构) IP指向的内存地址,取指令执行,完成后,IP值自加一,取下一条指令再执行. AP ...

  9. Linux内核分析——第六周学习笔记20135308

    第六周 进程的描述和进程的创建 一.进程描述符task_struct数据结构 1.操作系统三大功能 进程管理 内存管理 文件系统 2.进程控制块PCB——task_struct 也叫进程描述符,为了管 ...

随机推荐

  1. 【PAT】B1080 MOOC期终成绩(25 分)

    还是c++好用,三部分输入直接用相同的方法, 用map映射保存学生在结构体数组中的下标. 结构体保存学生信息,其中期末成绩直接初始化为-1, 注意四舍五入 此题还算简单 #include<ios ...

  2. chrony时间服务器

    chrony有着比ntp服务器更好的优势来同步服务,在集群架构中,采用此种服务来同步时间也是最好的方式. 在集群环境中,一般都是一个服务器,然后上百个客户端来同步服务端的时间,接下来我们看看如何配置. ...

  3. macOS平台安装metasploit

    1  在Github上克隆Metasploit git clone https://github.com/rapid7/metasploit-framework.git /usr/local/shar ...

  4. Flume-1.8.0_部署与常用案例

    该文章是基于 Hadoop2.7.6_01_部署 进行的 Flume官方文档:FlumeUserGuide 常见问题:记flume部署过程中遇到的问题以及解决方法(持续更新) 1. 前言 在一个完整的 ...

  5. C++基础算法学习——猜假币

    有12枚硬币.其中有11枚真币和1枚假币.假币和真币重量不同,但不知道假币比真币轻还是重.现在,用一架天平称了这些币三次,告诉你称的结果,请你找出假币并且确定假币是轻是重(数据保证一定能找出来).例题 ...

  6. Docker容器学习与分享12

    Docker多主机管理 之前在一台Centos7上安装了Docker,如果是在多台主机上都安装Docker,用手动安装的方法不光效率低下,而且有可能出错,所以可以使用Docker Machine进行多 ...

  7. Linux 小知识翻译 - 「TCP/IP」

    上次说了「协议」相关的话题,这次专门说说「TCP/IP」协议. 这里的主题是「TCP/IP」到底是什么?但并不是要说明「TCP/IP」是什么东西,重点是「TCP/IP」究竟有什么意义,在哪里使用「TC ...

  8. jQuery插件slider实现图片轮播

    1:引入相应的js文件  jquery.SuperSilder.js 2:HTML: 结构 注:此地加载图片的代码也可以从后台库中读取图片的集合列表,然后通过循环的方式显示出来 3:CSS 样式定义左 ...

  9. 启用crontab

    1.登录到root用户. 2.在root下输入:crontab -e 3.可能会提示你: no crontab for root - using an empty one 然后会叫你“Select a ...

  10. Intent加强

    Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件.通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意 ...