首页 > 系统服务 > 详细

2018-2019-1 20189204《Linux内核原理与分析》第七周作业

时间:2018-11-25 14:13:10      阅读:179      评论:0      收藏:0      [点我收藏+]

《庖丁解牛》第6章——进程的描述和进程的创建

前面两周对系统调用机制进行了仔细的研究,本周将学习用来创建进程的系统调用fork。首先,必须先理解进程如何描述(pcb),其次再理解进程的创建过程和机制。

一、学习内容及试验过程总结

6.1 进程的描述(由于此处的知识会与实验中研究数据结构struct task_struct的任务重复,所以将struct task_struct的知识统一放在实验任务中整理)

此处要主要掌握进程描述符的内容、状态转换和双向链表管理
1.OS内核实现OS的三大功能对应了OS原理课程中最重要的3个抽象概念:

  • 进程管理——进程
  • 内存管理——虚拟内存
  • 文件系统——文件
    其中最核心、最重要的功能就是进程管理
  1. 操作系统原理中使用PCB(Process Control Block,进程控制块)描述进程,也称作进程描述符,它提供了进程相关的所有信息。
    Linux内核中使用 数据结构struct task_struct来描述进程
    3.OS原理中的进程状态和Linux进程的状态的比较
  • OS原理中进程状态有三种:就绪、运行、阻塞
  • Linux内核中的进程状态有:
    • TASK_RUNNING:包括两种状态:进程就绪且没有运行、进程正在运行。这两种状态的区分取决于进程有没有获得CPU的分配权。
    • TASK_ZOMBIE:进程的终止状态,此状态的进程被称作僵尸进程,在此状态下的进程会被Linux内核在适当的时候处理掉,同时进程描述符也将被释放。
    • TASK_INTERRUPTIBLE :可以被信号或者是wake_up()唤醒。信号来临时,进程会被设置为TASK_RUNNING(仅仅是就绪状态而没有执行)
    • TASK_UNINTERRUPTIBLE:只能被wake_up()唤醒
      技术分享图片

6.2进程的创建

6.2.1 0号进程的初始化

双向链表中的第一个节点为init_task,这是第一个进程(0号进程)的进程描述符结构体变量,它的初始化是通过硬编码方式(宏定义,#difine INIT_TASK(tsk))固定下来的 。除此之外的其他所有进程的初始化都是通过do_fork复制父进程的方式初始化的。

6.2. 2 内存管理相关代码

1.内存管理的相关代码为struct mm_struct *mm,*active_mm;,mm和active_mm是和进程地址空间、内存管理相关的数据结构指针。
2.为了抓住Linux内核中最核心的工作机制,我们不仔细分析物理地址和逻辑地址转换、MMU的具体工作,将进程的地址空间简化为每个进程都有独立的逻辑地址空间。
3.32位x86体系结构拥有4GB的进程地址空间,用户态只能访问0x00000000~0xbfffffff的地址空间,0xc00000000以上的地址空间只能在内核态下访问。内核态可以访问全部4GB的地址空间。(详细可见《庖丁解牛》P68)

6.2.3 进程之间的父子、兄弟关系

在多达400+行的结构体struct task_struct代码中,进程描述符通过struct list_head tasks双向链表管理所有进程(list_head即是双向链表)

  • 当前进程的父进程:通过struct tast_struct __rcu *real_parent,struct task_struct __rcu *parent记录(不是双向链表)
  • 当前进程的子进程:通过struct list_head children记录(是双向链表)
  • 当前进程的兄弟进程:通过struct list_head sibling记录(是双向链表)
    这样设计数据结构是为了方便在内核代码中快速获取当前进程的父子、兄弟进程的信息

    6.2.4 保存进程上下文中CPU相关的一些状态信息的数据结构

    Linux内核中有与mykernel定义的thread相似的数据结构struct thread_struct,用来保存进程上下文中与CPU相关的一些状态信息,在进程切换是起着很重要的作用。
  • sp:保存进程上下文中的ESP寄存器状态
  • ip:保存进程上下文中的EIP寄存器状态
    此外进程描述符中还有和文件系统相关的数据结构、打开的文件描述符,有和信号处理相关以及和pipe管道相关的数据结构等。进程描述符可以在我们要研究Linux内核的某一部分的特定内容时起到提纲挈领的作用,诶我们进一步深入研究Linux内核提供了基础。

    6.2.5 进程的创建过程分析

    1.用户态创建进程的方法
    2.fork系统调用概览
    3.进程创建的主要过程
    4.内核堆栈关键信息的初始化
    5.通过实验跟踪分析进程创建的过程
    fork系统调用过程可以用一个图来在整体上展示系统调用的嵌套
    技术分享图片

二.实验楼中实验六——分析Linux内核创建一个新进程的过程

1.实验任务

  • 阅读理解task_struct数据结构http://codelab.shiyanlou.com/xref/linux-3.18.6/include/linux/sched.h#1235;
struct task_struct { 
volatile long state;        //进程状态/* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;                // 指定进程内核堆栈
pid_t pid;                  //进程标识符
unsigned int rt_priority;   //实时优先级
unsigned int policy;        //调度策略
struct files_struct *files; //系统打开文件
…
}
  • 分析fork函数对应的内核处理过程sys_clone,理解创建一个新进程如何创建和修改task_struct数据结构;
  • 使用gdb跟踪分析一个fork系统调用内核处理函数sys_clone ,验证您对Linux系统创建一个新进程的理解,推荐在实验楼Linux虚拟机环境下完成实验。 特别关注新进程是从哪里开始执行的?为什么从那里能顺利执行下去?即执行起点与内核堆栈如何保证一致。

    三、学习中遇到的问题

    markdown格式(.md文件)阅读器for windows

2018-2019-1 20189204《Linux内核原理与分析》第七周作业

原文:https://www.cnblogs.com/bowendky/p/9983166.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!