一、知识点总结

(一)进程的描述

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 long state; //运行状态
1237 void *stack; //进程的内核堆栈
1238 atomic_t usage;
1239 unsigned int flags;//每个进程的标识符 1240 unsigned int
#ifdef CONFIG_SMP //这部分是条件编译
1243 struct llist_node wake_entry;
1244 int on_cpu;
1245 struct task_struct *last_wakee;
1246 unsigned long wakee_flips;
1247 unsigned long wakee_flip_decay_ts;
.....
	struct list_head tasks; //这部分很关键,是进程的列表
1296#ifdef CONFIG_SMP
1297 struct plist_node pushable_tasks;
1298 struct rb_node pushable_dl_tasks;
1299#endif
1300
1301 struct mm_struct *mm, *active_mm;//和地址的内存空间,内存管理有关的,每个地址有独立的地址空间。
1302#ifdef CONFIG_COMPAT_BRK
1303 unsigned brk_randomized:1;
1304#endif
1305 /* per-thread vma caching */
1306 u32 vmacache_seqnum;
1307 struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309 struct task_rss_stat rss_stat;
1310#endif

链表的数据结构如下:

它是一个双向链表,参见include/linux/list.h
1330	pid_t pid;//进程的pid,来标识某一个进程
1331 pid_t tgid;
....
	/*
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_head children; /* list of my children */
1348 struct list_head sibling; /* 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使得进程运行完。

Linux内核分析 笔记六 进程的描述和进程的创建 ——by王玥的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. Linux内核分析实验六

    Linux内核分析实验六 进程控制块PCB——task_struct(进程描述符) 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. struct task_s ...

  7. Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质

    原文:Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质 Linux内核分析(六) 昨天我们对字符设备进行了初步的了解,并且实现了简单的字符设备驱动,今天我们继续对字符设备的某些方 ...

  8. 20135327郭皓--Linux内核分析第六周 进程的描述和进程的创建

    进程的描述和进程的创建 一.进程的描述 操作系统三大功能: 进程管理 内存管理 文件系统 进程描述符task_struct数据结构 task _ struct:为了管理进程,内核必须对每个进程进行清晰 ...

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

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

随机推荐

  1. Linux 小知识翻译 - 「单CD 的linux」

    这次聊聊「单CD Linux」. 所谓「单CD Linux」,就是不用安装,从CD-ROM启动后就可以使用的Linux. 有名的KNOPPIX就是「单CD Linux」,此外还有Puppy Linux ...

  2. BugBugBugBugBugBugBugBugBugBugBugBugBugBugBug

    单元测试

  3. 解决python中 .to_csv() 的乱码问题

    解决方法:添加参数 encoding='utf_8_sig' df.to_csv('users.csv', encoding='utf_8_sig')

  4. 为什么MySQL数据库索引选择使用B+树?

    在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择使 ...

  5. 阿里巴巴Java开发手册要点笔记 (一)

    1:[强制]Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals. 正例:"test".equals(object); 反例:obj ...

  6. 分布式缓存技术redis系列(五)——redis实战(redis与spring整合,分布式锁实现)

    本文是redis学习系列的第五篇,点击下面链接可回看系列文章 <redis简介以及linux上的安装> <详细讲解redis数据结构(内存模型)以及常用命令> <redi ...

  7. Qt+QGIS二次开发:读取矢量元素及其属性

    1  概述矢量图层内矢量元素组成,矢量图层的加载由驱动实现,驱动必须实现对矢量图层内元素的读写操作功能. 2 原理矢量元素包含几何和属性两部分组成.几何部分用于提供图形相关内容.属性部分提供与几何相关 ...

  8. SQL 公用表达式CTE

    一 基本用法 with mywith as(select * from Student ) select * from mywith 二 递归调用 with mywith as( select ID, ...

  9. C. Report

    题意:给出n个无序的数以及m个操作,每个操作由两个数组成,第一个数是操作的方式,第二个数 i 是操作的范围,若第一个数是1,则给 1-i 个数按升序排序,若第二个数是2,则给 1-i 个数按降序排列. ...

  10. TCP/IP与OSI模型