一、知识点总结

(一)进程的描述

1.操作系统内核里有三大功能:

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

2.进程描述符:task_struct

2.进程描述符——struct task_struct

1. pid_t pid又叫进程标识符,唯一地标识进程
2.双向循环链表链接起了所有的进程,也表示了父子、兄弟等进程关系 3. struct mm_struct 指的是进程地址空间,涉及到内存管理(对于X86而言,一共有4G的地址空间) 4. thread_struct thread 与CPU相关的状态结构体 5. struct *file表示打开的文件链表 6. Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_info和进程的内核堆栈

3.进程状态转换图

数据结构分析:

struct task_struct {
1236    volatile longstate;   //运行状态
1237    void *stack; //进程的内核堆栈
1238    atomic_tusage;
1239    unsigned intflags;//每个进程的标识符

1240  unsigned int
#ifdef CONFIG_SMP //这部分是条件编译
1243    struct llist_nodewake_entry;
1244    inton_cpu;
1245    struct task_struct *last_wakee;
1246    unsigned longwakee_flips;
1247    unsigned longwakee_flip_decay_ts;.....
struct list_headtasks; //这部分很关键,是进程的列表
1296#ifdef CONFIG_SMP
1297    struct plist_nodepushable_tasks;
1298    struct rb_nodepushable_dl_tasks;
1299#endif
1300
1301    struct mm_struct *mm, *active_mm;//和地址的内存空间,内存管理有关的,每个地址有独立的地址空间。
1302#ifdef CONFIG_COMPAT_BRK
1303    unsignedbrk_randomized:1;
1304#endif
1305    /* per-thread vma caching */
1306    u32vmacache_seqnum;
1307    struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309    struct task_rss_statrss_stat;
1310#endif链表的数据结构如下:
它是一个双向链表,参见include/linux/list.h
1330    pid_tpid;//进程的pid,来标识某一个进程
1331    pid_ttgid;....
/*
1338     * pointers to (original) parent process, youngest child, younger sibling,//进程的父子关系
1339     * older sibling, respectively.  (p->father can be replaced with
1340     * p->real_parent->pid)
1341     */
1342    struct task_struct __rcu *real_parent; /* real parent process */
1343    struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
1344    /*
1345     * children/sibling forms the list of my natural children
1346     */
1347    struct list_headchildren;   /* list of my children */
1348    struct list_headsibling; /* linkage in my parent's children list */ 1349 struct task_struct *group_leader; /* threadgroup leader */ 1350
...1411/* CPU-specific state of this task */
1412 struct thread_struct thread;//当前CPU相关的状态,在进程切换时起关键作用。

(二)进程的创建

  • 1.进程的状态以及fork一个进程的用户态代码
  • 2.fork系统调用在父进程和子进程各返回一次
  • 3.TASK_RUNNING具体是就绪还是执行,要看系统当前的资源分配情况
  • 4. TASK_ZOMBIE也叫僵尸进程

fork一个子进程的代码

  1. 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) //pid == 0和下面的else都会被执行到(一个是在父进程中即pid ==0的情况,一个是在子进程中,即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.}
    • iret与int 0x80指令对应,一个是弹出寄存器值,一个是压入寄存器的值
    • 如果将系统调用类比于fork();那么就相当于系统调用创建了一个子进程,然后子进程返回之后将在内核态运行,而返回到父进程后仍然在用户态运行
    • 回顾:系统调用的进程创建过程

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

1.一个新创建的子进程,(当它获得CPU之后)是从哪一行代码进程执行的?

  • 与之前写过的my_kernel相比较,kernel中是可以指定新进程开始的位置(也就是通过eip寄存器指定代码行)。fork中也有相似的机制
  • 这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copy_thread in copy_process

  • 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_thread复制父进程的PCB
      • copy_process修改复制的PCB以适应子进程的特点,也就是子进程的初始化
      • 分配一个新的内核堆栈(用于存放子进程数据)

        • 内核堆栈的一部分也要从父进程中拷贝

        • 根据拷贝的内核堆栈情况设置eip,esp寄存器的值

 

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

  1. 更新menu内核,然后删除test_fork.c以及test.c(以减少对之后实验的影响)

  1. 编译内核,可以看到fork命令

  1. 启动gdb调试,并对主要的函数设置断点

  1. 在MenuOS中执行fork,就会发现fork函数停在了父进程中

  2. 继续执行之后,停在了do_fork的位置。然后n单步执行,依次进入copy_process、dup_task_struct。按s进入该函数,可以看到dst =src(也就是复制父进程的struct)

3.在copy_thread中,可以看到把task_pg_regs(p)也就是内核堆栈特定的地址找到并初始化

     4.到了159、160行的代码就是把压入的代码再放到子进程中:

  • *children = *current_pt_regs();
    childregs->ax = 0;
  • 164行,是确定返回地址

    p->thread.ip = (unsigned long) ret_from_fork;
  • 最后,可以输入finish使得进程运行完。

转载于:https://www.cnblogs.com/disturbia/p/5332980.html

Linux内核分析 笔记六 进程的描述和进程的创建 ——by王玥相关推荐

  1. Linux内核分析 笔记二 操作系统是如何工作的 ——by王玥

    一.知识要点 1.计算机是如何工作的?(总结)--三个法宝 存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: 函数调用堆栈,高级语言得以运行的基础,只有机器语言和汇编语言的时候堆栈机制对于计算 ...

  2. Linux内核分析 笔记七 可执行程序的装载 ——by王玥

    一.预处理.编译.链接和目标文件的格式 (一)可执行程序是怎么得来的? 1. 2.可执行文件的创建--预处理.编译和链接 shiyanlou:~/ $ cd Code                  ...

  3. 庖丁解牛linux内核 百度云,庖丁解牛Linux内核分析笔记-1

    2019-5-3 主要内容摘自 孟宁<庖丁解牛Linux内核分析> 天下大事必作于细,天下难事必作于易 1.计算机三大法宝 存储程序计算机 函数调用堆栈 中断 2.虚拟一个x86的CPU硬 ...

  4. 庖丁解牛山linux内核的析,# 庖丁解牛Linux内核分析笔记-1

    2019-5-3 主要内容摘自 孟宁<庖丁解牛Linux内核分析> 天下大事必作于细,天下难事必作于易 1.计算机三大法宝 存储程序计算机 函数调用堆栈 中断 2.虚拟一个x86的CPU硬 ...

  5. Linux内核分析 - 网络[六]:网桥

    看完了路由表,重新回到netif_receive_skb ()函数,在提交给上层协议处理前,会执行下面一句,这就是网桥的相关操作,也是这篇要讲解的内容. [cpp] view plaincopy sk ...

  6. Linux内核分析期末总结

    <Linux内核分析>期末总结 20135313吴子怡.北京电子科技学院 Chapter1 往期博客传送门 (1)计算机是如何工作的:Linux内核分析--第一周学习笔记 (2)操作系统是 ...

  7. [网易云课堂]Linux内核分析(九)—— 课程总结

    付何山+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000; 导读:本文分为两个部分 ...

  8. 《Linux内核分析》 第六节 进程的描述和进程的创建

    <Linux内核分析> 第六节 进程的描述和进程的创建 20135307 张嘉琪 原创作品转载请注明出处 +<Linux内核分析>MOOC课程http://mooc.study ...

  9. Linux内核分析——进程的描述和进程的创建

    进程的描述和进程的创建 一. 进程的描述 (一)进程控制块PCB--task_struct 1.操作系统的三大管理功能包括: (1)进程管理 (2)内存管理 (3)文件系统 2.PCB task_st ...

最新文章

  1. antd 表单提交,文件和表单内容一起提交,表单校验
  2. gpupdate /force 遇报错解决过程
  3. SpringBootController控制层接收参数的几种常用方式
  4. BZOJ2199: [Usaco2011 Jan]奶牛议会
  5. SAP Spartacus component-wrapper自定义指令的实现
  6. dom4j读取XML文件内容
  7. 观察者模式Observer
  8. 设置android 触摸灵敏,3D Press触屏灵敏度设置教程 魅族PRO 6 3D Press触控力度怎么调...
  9. Unix下oracle备份,Linux下Oracle备份与数据迁移
  10. dcdc升压计算器excel_两款低压DC-DC升压转换器应用电路
  11. 百度冰桶算法2.0简介
  12. antd vue表单验证_解决antd 表单设置默认值initialValue后验证失效的问题
  13. vue keep-alive用法
  14. 万豪环保系列之《紫外线消毒器》
  15. 解决谷歌浏览器跨域以及cookie保存失效重复登录
  16. 生鲜电商运营框架的对比和分析
  17. css tabindex
  18. 内网渗透攻击技术的利用
  19. Just A Triangle
  20. Java基础03运算符

热门文章

  1. java-12:spring MVC - 控制反转IOC,依赖注入DI
  2. 基于wifi面向android的远程视频监控客户端开发,基于Wifi面向Android的远程视频监控客户端开发...
  3. 2.57亿美元:纸币打破了ICO资金的全部记录
  4. Jumpserver安装和测试连接
  5. “云”中智控 IT管理新境界
  6. 苹果称只保证直营店iPad补差价 近1周投诉急增
  7. 关于单片机对三极管B值的测量
  8. boj489. 小妹妹去划船
  9. C++程序员学习用C#写网站(四)
  10. 向凡客提议:建立ERP 深挖服装市场价值