张文俊 + 原创作品转载请注明出处 + 《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】B1050 螺旋矩阵(25 分)

    实在不觉得递归等方式有什么简单的地方,没错我就是用的最笨的方法模拟. 和我一样的小白看代码应该很容易理解. #include<stdio.h> #include<math.h> ...

  2. 软件工程实践_结对Task2_ student_department_matching

    1. 给出结对成员的学号及姓名. 结对成员 031502506 陈龙江 031502529 王国超 click 2.首页给出项目的Github链接. github:传送门 3. 贴出你们生成的一组最& ...

  3. 【转】struct和typedef struct在C/C++中的区别

    分三块来讲述: 1 首先://注意在C和C++里不同 在C中定义一个结构体类型要用typedef: typedef struct Student { int a; }Stu; 于是在声明变量的时候就可 ...

  4. C# 响应微信发送的Token验证,文字、图文自动回复、请求客服对话.....

    代码如下,有需要的可以参考: using System; using System.Collections.Generic; using System.Linq; using System.Web; ...

  5. centos7下安装docker(12.1bridge网络)

    容器默认使用的时bridge网络 docker安装时会创建一个 命令为docker0的linux bridge.如果不指定--network=,运行的容器会默认挂到docker0上 interface ...

  6. js中typeof与instanceof用法小记

    今天写JS代码,遇到动态生成多个名称相同的input复选按钮 需要判断其是否是数组,用到了if (typeof(document.MapCheckMgr.checkid)!="undefin ...

  7. heap堆算法的使用分析

    新生代  --复制算法 老年代 --标记压缩清除算法 分代 分区思想 垃圾回收的任务是识别和回收垃圾对象进行内存清理,为了让垃圾回收器可以高效的执行,大部分情况下,会要求系统进入一个停顿的状态. 停顿 ...

  8. linux 基础 用户操作

    命令: 1. whoami 2.su 用户名 3.useradd 用户名 4.passwd 用户名

  9. Android ScrollView和ListView联用,且ListView可以下拉刷新和上拉加载

    ScrollView嵌套listView且ListView可以实现上拉加载. 由于代码太长,在此只提供实现思路: 先不说上拉加载的事,咱们先回想一下,ScrollView和LsitView联用,时的解 ...

  10. 一篇文章让你彻底掌握 shell 语言

    一篇文章让你彻底掌握 shell 语言 由于 bash 是 Linux 标准默认的 shell 解释器,可以说 bash 是 shell 编程的基础. 本文主要介绍 bash 的语法,对于 linux ...