《Linux内核设计与实现》CHAPTER3阅读梳理

【学习时间:3hours】

【学习内容:进程的描述;进程的生命周期(包括创建、终结)】

一、进程(任务)描述

1.进程是处于执行期的程序;除了可执行程序代码,还包括打开的文件、挂起的信号、内核内部数据、一个或者多个执行线程等多种资源

  • 线程是在进程活动中的对象;内核调度的对象是线程而不是进程
  • 在Linux系统中,并不区分线程和进程
  • 可能存在两个或者多个进程执行的是同一个程序;甚至N个进程共享打开的文件、地址空间之类的资源

2.在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存

  • 同一进程中的线程之间可以共享虚拟内存,但是每个都拥有自己的虚拟存储器

3.进程概述

  1. 新创建的进程调用exec()这组函数就可以创建新的地址空间,并把新的程序载入其中;
  2. 最终,程序通过exit()函数可以退出执行;进程退出执行之后就会变为僵尸进程,直到父进程调用wait()或waitpid()(返回关于终止进程的状态)

二、进程描述符

1.进程描述符

  1. 进程列表存放在任务队列(task list)这一双向链表中
  2. 链表的项是task_struct也就是进程描述符类型的结构体
  3. 该类型定义在<linux/sched.h>中
  4. task_struct包含了进程所需的所有资源

2.分配与存放

  1. 目的:Linux通过slab分配task_struct结构,以达到对象复用以及和缓存着色的目的(避免资源动态分配和释放带来的资源消耗)
  2. 分配:每个任务的堆栈尾端(比如,对于向上增长的堆栈来说,就是在堆栈的栈顶)有结构体thread_info,它指向了task_struct结构体
  3. 查找:
    1. 内核中的大部分处理处理进程的代码都是通过task_struct进行的;因此,需要通过current宏查找到当前正在运行进程的进程描述符

    2. X86系统中,current把栈指针的后13个有效位屏蔽掉,用来计算出thread_info的偏移(通过current_thread_info函数)

       movl $-8192, %eax
      andl %esp,%eax

3.进程状态

  1. 进程在任何时刻,都必定处于五种状态中的一种

    • TASK_RUNNING
    • TASK_INTERRUPT
    • TASK_UNINTERRUPT
    • TASK_TRACED
    • TASK_STOPPED
  2. 状态转换图
    • TASK_RUNNING:可能是正在运行,也可能表示可执行

    • TASK_INTERRUPT/TASK_UNINTERRUPT:都表示正在阻塞;然而后者表示的状态收到信号之后也不会被唤醒

  3. 设置进程当前状态
    • 调用set_task_state(task,state)函数将进程设置为指定状态
  4. 进程上下文
    • 可执行代码从一个可执行文件载入到进程的地址空间执行。当一个程序执行了系统调用,内核就会“代表进程执行”并处于进程上下文中
    • 对比:在中断上下文中,系统不代表进程执行——不会有进程去干扰这些中断处理程序
  5. 进程继承关系
    • 所有的进程都是PID为1的init进程的后代

    • 对于给定的进程,获取链表中下一个进程:

        list_entry(task->tasks.prev,struct task_struct,tasks)

二、进程创建

1.Unix系统的进程创建方式

  1. fork()通过拷贝当前进程创建一个子进程
  2. exec()负责读取可执行文件并将其载入地址空间开始运行
  3. 写时拷贝
    • Linux的fork()使用写时拷贝推迟甚至免除拷贝。内核在创建新进程的时候并不复制整个地址空间,而是让父进程和子进程共享同一个拷贝;直到子进程/父进程需要写入的时候才进行拷贝
    • 因而,fork的实际开销只是复制父进程的页表以及给子进程创建唯一的进程描述符

2.fork函数

  1. Linux通过clone系统调用实现fork
  2. 由clone去调用do_fork()
  3. 定义在<kernel/fork.c>中的do_fork()完成创建中的大部分工作,它调用copy_process函数,然后让进程开始运行

【我认为,以下部分与本周视频讲课内容结合起来会有更好的理解效果】

最后,copy_process返回的就是指向子进程的指针

3.线程的创建

在Linux系统中,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都有自己的task_struct

  1. 创建线程:与普通进程类似,只不过在调用clone()的时候需要传递一些参数标志来指明共享的资源
  2. 内核线程:与普通进程的区别只在于内核线程没有独立的地址空间。
    • 它只能通过其他内核线程创建;内核通过kthread内核进程衍生所有的内核线程
    • 新创建的线程处于不可运行状态,直到wake_up_process()明确地唤醒它

三、进程终结

1.终结进程

该任务大部分依赖于do_exit(),该函数永不返回

2.删除进程描述符

  1. 该任务是和清理工作分开进行的,因为这样在进程终结之后系统仍然可以获得它的信息
  2. 通过release_task()实现进程描述符的删除
  3. 至此,所有资源都被释放了

3.解决孤儿进程

  1. 概述:父进程在进程之前退出,就会遗留下子进程,也就是孤儿进程
  2. 解决方法:在当前的线程组内给孤儿进程寻找新的父进程;否则直接以init作为其父进程
    • 调用顺序:do_exit()-->forget_original_parent()-->find_new_parent()-->ptrace_exit_finish()(这一函数是为被跟踪的进程寻找父进程,因为被跟踪的进程会以调试程序作为临时父亲)

疑问与自查

1.关于wait()与waitpid()函数?

参考http://no001.blog.51cto.com/1142339/493589

  1. wait函数的原型为:pid_t wait(int *status)

    当进程退出时,它向父进程发送一个SIGCHLD信号,默认情况下总是忽略SIGCHLD信号,此时进程状态一直保留在内存中,直到父进程使用wait函数收集状态信息,才会清空这些信息;
  2. 从本质上讲,系统调用waitpid是wait的封装,waitpid只是多出了两个可由用户控制的参数pid和options

2.什么是缓存着色?

参考http://blog.csdn.net/maray/article/details/3599845

主要就是起到区别CACHE LINE不同状态的作用

3.如何理解?

P23 进程管理-3.2.2

X86系统中,current把栈指针的后13个有效位屏蔽掉,用来计算出thread_info的偏移(通过current_thread_info函数)

参考http://blog.csdn.net/linwhwylb/article/details/6084461

因为esp和thread_info存在同一个块中,所以需要屏蔽掉esp来获得thread_info

《Linux内核分析》第六周 读书笔记的更多相关文章

  1. linux内核分析 第六周读书笔记

    第三章 进程管理 3.1 进程 进程:处于执行期的程序 线程是在进程活动中的对象:内核调度的对象是线程而不是进程,在Linux系统中,并不区分线程和进程 在现代操作系统中, 进程提供两种虚拟机制:虚拟 ...

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

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

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

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

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

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

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

    进程的描述和进程的创建 前言:以下笔记除了一些讲解视频中的概念记录,图示.图示中的补充文字.总结.分析.小结部分均是个人理解.如有错误观点,请多指教! PS.实验操作会在提交到MOOC网站的博客中写.

  6. linux内核分析 第八周读书笔记

    第四章 进程调度 4.1 多任务 1.多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 2.多任务操作系统使多个进程处于堵塞或者睡眠状态,实际不被投入执行,这些任务尽管位于内存,但是并不处于 ...

  7. linux内核分析 第七周读书笔记

    第七章 链接 1.链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载到存储器并执行. 2.链接可以执行于编译时,加载时,运行时. 7.1编译器驱动程序 1.大多数编译系统 ...

  8. linux内核分析 第五周读书笔记

    第18章 调试 内核调试的难度大于用户级 一.准备开始 开始之前需要的是: 一个行为可靠且定义明确的bug 一个隐匿bug的内核版本 相关内核代码的知识和运气 想要成功的调试,取决于能不能将这些bug ...

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

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

  10. Linux内核分析第四章 读书笔记

    Linux内核分析第四章 读书笔记 第一部分--进程调度 进程调度:操作系统规定下的进程选取模式 面临问题:多任务选择问题 多任务操作系统就是能同时并发地交互执行多个进程的操作系统,在单处理器机器上这 ...

随机推荐

  1. jQuery Ajax遍历表格,填充数据,将表格中的数据一条一条拼成Jason数组

    $.ajax({ url: baseURL + "InvoiceSale/OnQuotaInvoiceSale", //点击核销单号时,点击核销时,交互的页面           ...

  2. HDU - Travel

    Problem Description Jack likes to travel around the world, but he doesn’t like to wait. Now, he is t ...

  3. Codeforce - Street Lamps

    Bahosain is walking in a street of N blocks. Each block is either empty or has one lamp. If there is ...

  4. BZOJ 1045 题解

    1045: [HAOI2008] 糖果传递 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3502  Solved: 1623[Submit][Sta ...

  5. FS210开发板上Qt4.7.0移植过程

    作者:冯老师,华清远见嵌入式学院讲师. 1. 搭建Qt开发环境平台 1.开发环境:ubuntu 12.04 2.交叉编译链:arm-cortex_a8-linux-gnueabi 3.开发板:FS21 ...

  6. Java_Java Compiler 应用实例

    转自:http://hejiangtao.iteye.com/blog/1399122 一直在用JDK1.5, 一直搞不清楚JDK1.6有啥特性, 就翻了翻, 发现这个Compiler API(JSR ...

  7. 转载:C# this.Invoke()的作用与用法 理解三

    Invoke()的作用是:在应用程序的主线程上执行指定的委托.一般应用:在辅助线程中修改UI线程( 主线程 )中对象的属性时,调用this.Invoke();   在多线程编程中,我们经常要在工作线程 ...

  8. java中instanceof和getClass()的区别分析

    class A { } class B extends A { } Object o1 = new A();  Object o2 = new B(); o1 instanceof A => t ...

  9. 选择Nodejs的N个理由

    选择Nodejs的N个理由 作者 马德奎 发布于 2014年9月25日 Caleb Madrigal是 来自美国密尔沃基市的一名软件顾问.四年前,他在听说“将JavaScript用作服务器端语言”这样 ...

  10. Java基础:继承,封装,多态,抽象类,接口

    只要是从事Java语言有关的开发工作,在面试中难念会被问到这几个东西. 博主学习java有两年多了,算是浅显的知道一些,抄写了一些解释分享一下. 1.什么是面向对象?(面对女朋友) 面向对象(Obje ...