Linux操作系统分析 中国科学技术大学计算机系 陈香兰(0512- )

Slides:



Advertisements
Similar presentations
Linux 操作系统分析 中国科学技术大学计算机系 陈香兰( 0512 - ) Autumn 2010.
Advertisements

7.1 内置对象概述及分类 JSP 视频教学课程. JSP2.2 目录 1. 内置对象简介 1. 内置对象简介 2. 内置对象分类 2. 内置对象分类 3. 内置对象按功能区分 3. 内置对象按功能区分 4. 内置对象作用范围 4. 内置对象作用范围.
高级服务器设计和实现 1 —— 基础与进阶 余锋
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Process Scheduling based on Linux3.2 孟宁 电话: 孟宁 V5 : 主页:
1 张惠娟 副教授 Linux 进程管理. 2 内容 进程组成 进程环境 进程管理内容 进程控制块 进程状态 进程调度 进程控制 进程通信.
Linux 系统. 操作系统发展需求 1 没有操作系统 2 简单批处理操作系统 3 多道程序设计的批处理 4 多道程序设计的分时操作系统 5 多处理机并行系统 6 网络操作系统 7 分布式操作系统.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
孟宁 电话: 主页:
Oracle数据库 Oracle 子程序.
Lab2 syscall 参数问题 参数check在当前代码框架下并不具有任何含义, 它就只是个参数而已 参数不超过四个: 系统调用号
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
实践演练 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
走进编程 程序的顺序结构(二).
辅导课程六.
中国科学技术大学计算机系 陈香兰(0551- ) Spring 2009
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
中国科学技术大学计算机系 陈香兰(0512- ) Autumn 2011
中国科学技术大学计算机系 陈香兰(0512- ) Autumn 2009
中国科学技术大学计算机系 陈香兰(0512- ) Autumn 2010
Online job scheduling in Distributed Machine Learning Clusters
中国科学技术大学计算机系 陈香兰(0512- ) Sprint 2011
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
CPU结构和功能.
中国科学技术大学计算机系 陈香兰(0551- ) Spring 2009
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
Linux内核源代码导读 中国科学技术大学计算机系 陈香兰(0551- )
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
内容摘要 ■ 课程概述 ■ 教学安排 ■ 什么是操作系统? ■ 为什么学习操作系统? ■ 如何学习操作系统? ■ 操作系统实例
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
顺序表的删除.
实验一 体验Nachos下的并发程序设计 陈毅东 2006年春.
进程概念.
姚金宇 MIT SCHEME 使用说明 姚金宇
Linux操作系统分析 中国科学技术大学计算机系 陈香兰(0512- )
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
Web安全基础教程
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
信号量(Semaphore).
第4章 Excel电子表格制作软件 4.4 函数(一).
iSIGHT 基本培训 使用 Excel的栅栏问题
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
临界区问题的硬件指令解决方案 (Synchronization Hardware)
GIS基本功能 数据存储 与管理 数据采集 数据处理 与编辑 空间查询 空间查询 GIS能做什么? 与分析 叠加分析 缓冲区分析 网络分析
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Python 环境搭建 基于Anaconda和VSCode.
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
主讲:陈香兰 助教:贾永泉、毛熠璐 (西区电三421) Autumn 2007
阻塞式模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 UNIX文件系统.
第十七讲 密码执行(1).
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
本节内容 SEMAPHORE 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
Presentation transcript:

Linux操作系统分析 中国科学技术大学计算机系 陈香兰(0512-87161312) xlanchen@ustc.edu.cn 助教:裴建国、冯晓静 Autumn 2008

Linux的进程

主要内容 进程描述符 进程切换 进程的创建和删除 进程调度 2019/1/1 Linux OS Analysis

主要内容 进程描述符 进程切换 进程的创建和删除 进程调度 2019/1/1 Linux OS Analysis

进程和线程 多道程序对操作系统的需求进程 进一步提高并发度,对操作系统的需求 线程 进程是执行程序的一个实例 进程和程序的区别 几个进程可以并发的执行一个程序 一个进程可以顺序的执行几个程序 线程和进程的区别 Linux 2.4内核以及之前的版本都不支持线程 Linux中的线程是在用户态实现的,不是本课程的内容 2019/1/1 Linux OS Analysis

进程描述符 为了管理进程,内核必须对每个进程进行清晰的描述。 进程描述符提供了内核所需了解的进程信息 include/linux/sched.h struct task_struct 数据结构很庞大 基本信息 管理信息 控制信息 2019/1/1 Linux OS Analysis

2019/1/1 Linux OS Analysis

Linux进程的状态 可运行状态(TASK_RUNNING) 可中断的等待状态(TASK_INTERRUPTIBLE) 不可中断的等待状态(TASK_UNINTERRUPTIBLE) 暂停状态(TASK_STOPPED) 僵死状态(TASK_ZOMBIE) 状态值的改变通常是一个简单的赋值 内核也提供set_task_state 和set_current_state 宏 2019/1/1 Linux OS Analysis

进程状态转换图 2019/1/1 Linux OS Analysis

标识一个进程 使用进程描述符地址 使用PID (Process ID,PID) 进程和进程描述符之间有非常严格的一一对应关系,使得用32位进程描述符地址标识进程非常方便 使用PID (Process ID,PID) 每个进程的PID都存放在进程描述符的pid域中 0~32767 新pid的产生:get_pid +1 循环 2019/1/1 Linux OS Analysis

内核函数get_pid的算法 pid空间:0~32767 可用pid窗口 初始:1~32767 在可用pid窗口中,依次分配 首先顺时针循环确定窗口起点 然后根据起点,采用逐次缩小范围法,确定窗口终点 窗口起点,last_pid+1 采用++,依次分配 窗口终点,next_safe-1 采用++,依次分配 0 1 2 3 2019/1/1 Linux OS Analysis 32767

用户如何获得一个进程的pid 系统调用getpidsys_getpid 关于进程组 单独一个进程可以看成只有一个进程的组 使用组链表 所有进程共享组内第一个进程的pid 数据:tgid 单独一个进程可以看成只有一个进程的组 getpid返回组pid 2019/1/1 Linux OS Analysis

进程描述符和进程的内核堆栈 Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构: 进程描述符 进程的内核堆栈 进程处于内核态时使用, 不同于用户态堆栈 内核控制路径所用的堆栈 很少,因此对栈和描述符 来说,8KB足够了 2019/1/1 Linux OS Analysis

Task_union C语言允许用如下的一个union结构来方便的表示这样的一个混合体 进程描述符的分配/回收/访问 alloc_task_struct free_task_struct get_task_struct =2048 2019/1/1 Linux OS Analysis

current宏进程描述符 从刚才看到的进程描述符和内核态堆栈之间的配对,内核可以很容易的从esp寄存器的值获得当前在CPU上运行的进程的描述符指针 因为这个内存区是8KB=213大小,内核必须做的就是让esp有13位的有效位,以获得进程描述符的基地址 这个工作由current宏来完成 8191=8192-1=0x2000-1=0x1fff 取反:0xffffe000(最后13位为0) 2019/1/1 Linux OS Analysis

Current宏的使用 Current宏可以看成当前进程的进程描述符指针,在内核中直接使用 举例: 比如current->pid返回在CPU上正在执行的进程的PID 2019/1/1 Linux OS Analysis

进程链表 为了对给定类型的进程(比如所有在可运行状态下的进程)进行有效的搜索,内核维护了几个进程链表 所有进程链表 在进程描述符中: 2019/1/1 Linux OS Analysis

SET_LINKS和REMOVE_LINKS宏用来分别在进程链表中插入和删除一个进程描述符。 2019/1/1 Linux OS Analysis

for_each_task宏扫描整个进程链表 2019/1/1 Linux OS Analysis

当内核调度程序寻址一个新的进程在cpu上运行时,必须只考虑可运行进程,因为扫描整个进程链表效率很低 TASK_RUNNING状态的进程链表 当内核调度程序寻址一个新的进程在cpu上运行时,必须只考虑可运行进程,因为扫描整个进程链表效率很低 引入了可运行状态的双向循环链表,也叫运行队列 进程描述符使用 用来实现运行队列 2019/1/1 Linux OS Analysis

… 对可运行队列的一些操作函数 增加/删除一个可运行进程 可运行队列的长度,可运行进程的个数 唤醒一个进程,使一个进程可运行 2019/1/1 Linux OS Analysis

pidhash表及链接表 在一些情况下,内核必须能从进程的PID得出对应的进程描述符指针。例如kill系统调用 用pid_hashfn宏把PID转换成表的索引 2019/1/1 Linux OS Analysis

pidhash表及链接表 2019/1/1 Linux OS Analysis

进程之间的亲属关系 程序创建的进程具有父子关系,在编程时往往需要引用这样的父子关系。进程描述符中有几个域用来表示这样的关系 2019/1/1 Linux OS Analysis

等待队列 当要把除了TASK_RUNNING状态之外的进程组织在一起时,linux使用了等待队列 TASK_STOPPED和TASK_ZOMBIE不在专门的链表中 TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE状态的进程再分成很多类,每一类对应一个特定的事件。在这种情况下,进程状态提供的信息满足不了快速检索,因此,内核引进了另外的进程链表,叫做等待队列 等待队列在内核中有很多用途,尤其是对中断处理、进程同步和定时用处很大 2019/1/1 Linux OS Analysis

等待队列使得进程可以在事件上的条件等待,并且当等待的条件为真时,由内核唤醒它们 等待队列由循环链表实现 在等待队列上内核实现了一些操作函数 Add_wait_queue remove_wait_queue 2019/1/1 Linux OS Analysis

等待队列的链表 2019/1/1 Linux OS Analysis

进程等待 等待一个特定事件的进程能调用下面几个函数中的任一个 进程等待由需要等待的进程自己进行(调用) sleep_on sleep_on_timeout interruptible_sleep_on interruptible_sleep_on_timeout 进程等待由需要等待的进程自己进行(调用) 2019/1/1 Linux OS Analysis

sleep_on 2019/1/1 Linux OS Analysis

进程的唤醒 利用wake_up或者wake_up_interruptible等一系列的宏,都让插入等待队列中的进程进入TASK_RUNNING状态 2019/1/1 Linux OS Analysis

主要内容 进程描述符 进程切换 进程的创建和删除 进程调度 2019/1/1 Linux OS Analysis

进程切换(process switching) 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换,任务切换,上下文切换 2019/1/1 Linux OS Analysis

进程上下文 包含了进程执行需要的所有信息 用户地址空间 包括程序代码,数据,用户堆栈等 控制信息 进程描述符,内核堆栈等 硬件上下文 2019/1/1 Linux OS Analysis

尽管每个进程可以有自己的地址空间,但所有的进程只能共享CPU的寄存器。 硬件上下文 尽管每个进程可以有自己的地址空间,但所有的进程只能共享CPU的寄存器。 因此,在恢复一个进程执行之前,内核必须确保每个寄存器装入了挂起进程时的值。这样才能正确的恢复一个进程的执行 硬件上下文: 进程恢复执行前必须装入寄存器的一组数据 包括通用寄存器的值以及一些系统寄存器 通用寄存器如eax,ebx等 系统寄存器如eip,esp,cr3等等 2019/1/1 Linux OS Analysis

在linux中 一个进程的硬件上下文主要保存在thread_struct中 其他信息放在内核态堆栈中 2019/1/1 Linux OS Analysis

thread_struct 2019/1/1 Linux OS Analysis

上下文切换 switch_to宏执行进程切换,schedule()函数调用这个宏一调度一个新的进程在CPU上运行 在schedule()中找到调用switch_to宏的位置 switch_to利用了prev和next两个参数: prev:指向当前进程 next:指向被调度的进程 2019/1/1 Linux OS Analysis

从next的上下文中取出堆栈的位置,将其作为当前堆栈 %0是什么? 堆栈被切换 当前进程仍然是prev 这个push操作针对的是 当前进程的堆栈 保存esi,edi,ebp 保存esp到当前进程的上下文中 保存esp到%0中 从next的上下文中取出堆栈的位置,将其作为当前堆栈 %0是什么? 堆栈被切换 在prev进程的上下文中设置返回地址,返回到下面标号为1处 从next进程的上下文中取得该进程的返回地址,放入堆栈中 内联汇编中 用这种方法表 示输入、输出 参数,可以从 0开始编号 调用__switch_to函数 关于内联汇编,请参考http://gcc.gnu.org/onlinedocs/上的文档: 1)在GCC的文档中有部分 2)在GNAT的文档中有说明 2019/1/1 Linux OS Analysis

进程切换的关键语句 堆栈的切换 从此,内核对next的内核态堆栈操作,因此,这条指令执行从prev到next真正的上下文切换,因为进程描述符和内核态堆栈紧密联系在一起,改变内核态堆栈就意味改变当前进程 2019/1/1 Linux OS Analysis

什么时候next进程真正开始执行呢? call=保存返回地址+跳转到target处执行 ret=从堆栈上获得返回地址,并跳转到该返回地址处执行 ?当__switch_to正常返回时,发生了什么事情? 2019/1/1 Linux OS Analysis

标号为1的执行代码处 一个进程被正常切换出时,保存的eip总是标号为1的那个位置 当这个进程再次被调度运行时,恢复在堆栈上的返回地址总是这个1 1: popl %ebp popl %edi popl %esi 2019/1/1 Linux OS Analysis

__switch_to __switch_to用来处理其他上下文的切换 此时,使用的堆栈是next进程的堆栈,这个堆栈上没有__switch_to需要的参数prev和next 怎么传参呢? 找到__switch_to的函数定义和函数声明 找到FASTCALL的定义 2019/1/1 Linux OS Analysis

__switch_to的关键操作 unlazy_fpu() 处理数学协处理器 保存和恢复fs、gs 等等 2019/1/1 Linux OS Analysis

?哪里切换了进程的地址空间 从执行switch_to的位置往前找 2019/1/1 Linux OS Analysis

Project:进程的切换 对Linux中进程的切换过程进行分析,提交分析报告 2019/1/1 Linux OS Analysis

主要内容 进程描述符 进程切换 进程的创建和删除 进程调度 2019/1/1 Linux OS Analysis

进程的创建 许多进程可以并发的运行同一程序,这些进程共享内存中程序正文的单一副本,但每个进程有自己的单独的数据和堆栈区 一个进程可以在任何时刻可以执行新的程序,并且在它的生命周期中可以运行几个程序 又如,只要用户输入一条命令,shell进程就创建一个新进程 2019/1/1 Linux OS Analysis

传统的UNIX操作系统采用统一的方式来创建进程 缺点: 子进程复制父进程所拥有的资源 缺点: 创建过程慢、效率低 事实上,子进程复制的很多资源是不会使用到的 现代UNIX内核通过引入三种不同的机制来解决这个问题 2019/1/1 Linux OS Analysis

1、写时复制技术,Copy-On-Writing,COW 写时复制技术允许父子进程能读相同的物理页。 只要两者有一个进程试图写一个物理页,内核就把这个页的内容拷贝到一个新的物理页,并把这个新的物理页分配给正在写的进程 2019/1/1 Linux OS Analysis

2、轻量级进程允许父子进程共享许多数据结构 页表 打开的文件列表 信号处理 3、vfork 使用vfork创建的新进程能够共享父进程的内存地址空间。父进程在这个过程中被阻塞,直到子进程退出或者执行一个新的程序 2019/1/1 Linux OS Analysis

Linux的进程创建 Linux提供了几个系统调用来创建和终止进程,以及执行新程序 Fork,vfork和clone系统调用创建新进程 exec系统调用执行一个新程序 exit系统调用终止进程(进程也可以因收到信号而终止) 2019/1/1 Linux OS Analysis

fork fork系统调用创建一个新进程 fork系统调用为父子进程返回不同的值 调用fork的进程称为父进程 新进程是子进程 子进程几乎就是父进程的完全复制。它的地址空间是父进程的复制,一开始也是运行同一程序。 fork系统调用为父子进程返回不同的值 2019/1/1 Linux OS Analysis

exec 很多情况下,子进程从fork返回后很多会调用exec来开始执行新的程序 这种情况下,子进程根本不需要读或者修改父进程拥有的所有资源。 所以fork中地址空间的复制依赖于Copy On Write技术,降低fork的开销 2019/1/1 Linux OS Analysis

使用fork和exec的例子 If (result = fork() == 0){ /* 子进程代码 */ … if (execve(“new_program”,…)<0) perror(“execve failed”); exit(1); }else if (result<0){ perror(“fork failed”) } /* result==子进程的pid,父进程将会从这里继续执行*/ 2019/1/1 Linux OS Analysis

分开这两个系统调用是有好处的 若单一的系统调用试图完成所有这些功能将是笨重而低效的 比如服务器可以fork许多进程执行同一个程序 有时程序只是简单的exec,执行一个新程序 在fork和exec之间,子进程可以有选择的执行一系列操作以确保程序以所希望的状态运行 重定向输入输出 关闭不需要的打开文件 改变UID或是进程组 重置信号处理程序 若单一的系统调用试图完成所有这些功能将是笨重而低效的 现有的fork-exec框架灵活性更强 清晰,模块化强 2019/1/1 Linux OS Analysis

do_fork 不论是fork,vfork还是clone,在内核中最终都调用了do_fork 2019/1/1 Linux OS Analysis

2019/1/1 Linux OS Analysis

???子进程从哪里开始执行,它的返回值是什么? 阅读do_fork,了解大致程序流程 ???子进程从哪里开始执行,它的返回值是什么? 观察子进程的初始上下文是怎么设置的 内核堆栈的内容 Thread_struct的内容 2019/1/1 Linux OS Analysis

此后,由于子进程处于调度队列上,因此在合适的时候会被调度, 调度时根据这里设置的上下文返回 用户态 注意:childregs指针指向哪里 eax寄存器用作返回值,这里强制为0 在上下文中,设置用户态堆栈指针 设置内核态堆栈指针 被调度后,执行入口 强制从ret_from_fork返 回用户态 此后,由于子进程处于调度队列上,因此在合适的时候会被调度, 调度时根据这里设置的上下文返回 用户态 2019/1/1 Linux OS Analysis

子进程的内核态堆栈 用户态堆栈esp的值 用户态下eip的值 子进程恢复到用户态时需要的上下文 返回值eax被强制写0 esp eip 子进程的8K union 高地址 用户态堆栈esp的值 子进程的硬件上下文 用户态下eip的值 子进程恢复到用户态时需要的上下文 返回值eax被强制写0 esp ret_from_fork eip 进程描述符 esp 低地址 2019/1/1 Linux OS Analysis

子进程的执行 fork后,子进程处于可运行状态,由调度器决定何时把CPU交给这个子进程 进程切换后因为eip指向ret_from_fork,所以CPU立刻跳转到ret_from_fork()去执行。 接着这个函数调用ret_from_sys_call(),此函数用存放在栈中的值装载所有寄存器,并强迫CPU返回用户态 回忆进程的切换 2019/1/1 Linux OS Analysis

内核线程 系统把一些重要的任务委托给周期性执行的进程 内核线程与普通进程的差别 刷新磁盘高速缓存 交换出不用的页框 维护网络链接等待 每个内核线程执行一个单独指定的内核函数 只运行在内核态 只使用大于PAGE_OFFSET的线性地址空间 2019/1/1 Linux OS Analysis

线程和进程的比较 Linux内核中没有线程的概念 在其他系统中(比如windows) 没有针对所谓线程的调度策略 没有数据结构用来表示一个线程 一般线程的概念在linux中只是表现为一组共享资源的进程(每个这样的进程都有自己的进程描述符) 在其他系统中(比如windows) 线程是实实在在的一种运行抽象,提供了比进程更轻更快的调度单元 在linux中“线程”仅仅是表示多个进程共享资源的一种说法 2019/1/1 Linux OS Analysis

创建内核线程 Kerenl_thread()创建一个内核线程,并且只能由另一个内核线程来执行这个调用 2019/1/1 Linux OS Analysis

进程树 进程0 进程1 … 2019/1/1 Linux OS Analysis

进程0 所有进程的祖先叫做进程0 在系统初始化阶段由start_kernel()函数从无到有手工创建的一个内核线程 存放在init_task_union变量中的一个进程描述符和一个内核态堆栈(回忆一下启动时,堆栈的初始化) 用INIT_MM, INIT_MMAP, INIT_FS, INIT_FILES, INIT_SIGNALS宏初始化进程描述符的各个对应域 页全局目录,swapper_pg_dir变量 进程0最后的初始化工作创建init内核线程,此后运行cpu_idle,成为idle进程 2019/1/1 Linux OS Analysis

由进程0在start_kernel调用rest_init创建 进程1 又称为init进程 由进程0在start_kernel调用rest_init创建 init进程PID为1,当调度程序选择到init进程时,init进程开始执行init()函数 2019/1/1 Linux OS Analysis

init() 为常规内核任务初始化一些必要的内核线程,如: kflushd 刷新‘脏’缓冲区中的内容到磁盘以归还内存 kswapd 执行内存回收功能的线程 最后init()函数调用execve()系统调用装入可执行程序init。从此,init内核线程变成一个普通的进程。但init进程从不终止,因为它创建和监控操作系统外层的所有进程的活动 2019/1/1 Linux OS Analysis

撤销进程 进程终止 进程终止的一般方式是exit()系统调用。 内核可以强迫进程终止 这个系统调用可能由编程者明确的在代码中插入 另外,在控制流到达主过程[C中的main()函数]的最后一条语句时,执行exit()系统调用 内核可以强迫进程终止 当进程接收到一个不能处理或忽视的信号时 当在内核态产生一个不可恢复的CPU异常而内核此时正代表该进程在运行 2019/1/1 Linux OS Analysis

删除进程 在父进程调用wait()类系统调用检查子进程是否合法终止以后,就可以删除这个进程 进程终止使用exit系统调用 删除进程 在父进程调用wait()类系统调用检查子进程是否合法终止以后,就可以删除这个进程 2019/1/1 Linux OS Analysis

Project:进程的创建 使用C语言编写一段用户程序 目的:从用户态体验进程的创建 对Linux中进程的创建进行分析,提交分析报告 调用fork创建一个子进程 然后让子进程和父进程分别输出fork的返回值 目的:从用户态体验进程的创建 对Linux中进程的创建进行分析,提交分析报告 2019/1/1 Linux OS Analysis

主要内容 进程描述符 进程切换 进程的创建和删除 进程调度 2019/1/1 Linux OS Analysis

进程的分类 不同类型的进程有不同的调度需求 第一种分类: I/O-bound CPU-bound 频繁的进行I/O 计算密集型 需要大量的CPU时间进行运算 2019/1/1 Linux OS Analysis

第二种分类 交互式进程(interactive process) 需要经常与用户交互,因此要花很多时间等待用户输入操作 响应时间要快,平均延迟要低于50~150ms 典型的交互式程序:shell、文本编辑程序、图形应用程序等 2019/1/1 Linux OS Analysis

实时进程(real-time process) 批处理进程(batch process) 不必与用户交互,通常在后台运行 不必很快响应 典型的批处理程序:编译程序、科学计算 实时进程(real-time process) 有实时需求,不应被低优先级的进程阻塞 响应时间要短、要稳定 典型的实时进程:视频/音频、机械控制等 2019/1/1 Linux OS Analysis

Linux中的进程调度 Linux既支持普通的分时进程,也支持实时进程 Linux中的调度是多种调度策略和调度算法的混合。 什么是调度策略? 是一组规则,它们决定什么时候以怎样的方式选择一个新进程运行 Linux中的调度策略(scheduling policy) Linux中的调度算法 2019/1/1 Linux OS Analysis

Linux的调度策略 Linux进程可以指定该进程所采用的调度策略 调度算法根据进程的调度策略,采用不同的调度算法 普通的分时进程 先入先出的实时进程 循环轮转的实时进程 当一个进程自动放弃运行时设置 2019/1/1 Linux OS Analysis

Linux的调度主要基于分时技术 允许多个进程“并发”运行 CPU的时间被划分成“片”,给每个可运行进程分配一片 在单处理器上,任何时刻只能运行一个进程,当一个并发执行的进程时间片用完时(到期)还没有终止,就可以进行进程调度 分时依赖于时钟中断,对进程透明 2019/1/1 Linux OS Analysis

Linux进程的调度优先级 Linux在其调度程序中,根据特定的算法计算出进程的调度优先级,用一个值goodness表示,进程根据这个值竞争CPU Linux中进程的优先级是动态的 调度程序会根据进程的行为周期性的调整进程的优先级 较长时间未分配到CPU的进程,通常↑ 已经在CPU上运行了较长时间的进程,通常↓ 2019/1/1 Linux OS Analysis

时间片的选择 时间片的长短对系统性能非常关键,它既不能太长也不能太短 太短: 频繁的切换会造成系统开销过大 假如切换时间为1ms,时间片设置为1ms,那就没空执行进程了 2019/1/1 Linux OS Analysis

时间片大小的选择总是一种折衷。Linux采取单凭经验的方法,即选择尽可能长的时间片,同时能保持良好的响应时间 太长 几乎每个进程都一次运行完 并发的概念基本消失 普通进程需要等待很长时间才能运行 时间片大小的选择总是一种折衷。Linux采取单凭经验的方法,即选择尽可能长的时间片,同时能保持良好的响应时间 2019/1/1 Linux OS Analysis

与调度相关的系统调用 nice getpriority/setpriority sched_getscheduler/sched_setscheduler sched_getparam/sched_setparam sched_yield sched_get_priority_min/sched_get_priority_max sched_rr_get_interval 2019/1/1 Linux OS Analysis

Linux的调度算法(1) epoch linux调度算法把CPU时间划分为时期(epoch) 在一个单独的时期内,每个进程有一个指定的时间片 一个进程用完它的时间片时,就会被强占 只要进程的时间片没有用完,就可以被多次调度运行 当所有的进程用完它的时间片的时候,一个时期才结束,此时要重新计算所有进程的时间片,并重新开始一个新的时期 2019/1/1 Linux OS Analysis

Linux的调度算法(2) 基本时间片(base time quantum) 每个进程有一个基本时间片,通过nice计算 时间片/epoch到期时,新时间片的计算公式: 可以通过nice、setpriority系统调用调整进程的基本时间片 nice缺省为0(在-20到19之间选择) 通常,基本时间片的值 为6,由于时钟中断大约10ms左右, 因此基本时间片的长度大约60ms 2019/1/1 Linux OS Analysis

Linux的调度算法(3) 当前剩余时间片 每个进程使用counter表示当前时期内的剩余时间片 每当一个tick过去,就会从当前进程的counter上-1 在某个时期内创建的一个新进程,在该时期内的剩余时间片将从父进程那里继承一半 2019/1/1 Linux OS Analysis

举例:进程0(INIT_TASK)的时间片: HZ代表了1秒内的tick数 因此一个tick就是1/100秒 即10ms 可以计算出 DEF_COUNTER=10个tick 即100ms (实际上约105ms) MAX_COUNTER=20个tick 即200ms 2019/1/1 Linux OS Analysis

调度程序使用的数据结构 进程描述符中: need_resched:是否需要调度 policy:调度策略 rt_priority:实时进程的静态优先级(1~99),普通进程不用(设为0) counter:当前剩余时间片 新时期开始时根据上述计算公式计算 每次时钟中断,时间片都会-1,直到为0(则请求调度) 创建一个新进程时,子进程会继承父进程的一半剩余时间片 nice:基本时间片参数,可以调节 2019/1/1 Linux OS Analysis

schedule函数 schedule函数实现调度 目的:在运行队列中找到一个进程,把CPU分配给它 调用方法: 阅读schedule 直接调用,如sleep_on 松散调用,根据need_resched标记 阅读schedule 2019/1/1 Linux OS Analysis

调度的时机 调度时机来临时,内核或驱动将调用schedule() 在Linux中调度的时机主要有: current的状态从running转换为其他状态时,如: 1)进程终止。exit()在最后调用schedule()。 2)进程因某种原因进入等待状态。 比较常见的就是进程调用nanosleep()或者wait系列的系统调用。 此外,在设备驱动程序中,最常见的原因就是驱动引发一次I/O操作后,为等待I/O操作的结束而进入等待状态。多数情况下,驱动会直接调用schedule()。 2019/1/1 Linux OS Analysis

进程从中断、异常、系统调用状态(即内核态)返回时。 当前进程的时间片用完时。 时间片是否用完,由时钟中断处理程序进行判断。 若到期,就将current的need_resched位置1。 返回用户态时,根据need_resched调用schedule() 进程从中断、异常、系统调用状态(即内核态)返回时。 若在中断、异常、系统调用中,current的need_resched被置1,都会导致进程调度。 包括上述时钟中断。 2019/1/1 Linux OS Analysis

调度算法的性能 不适合进程数量很大的情况 对高负载系统来说,预定义的时间片太长 对于I/O密集型的程序不是很有利 对实时应用的支持是微弱的 重新计算所有进程的动态优先级很耗时 对高负载系统来说,预定义的时间片太长 对于I/O密集型的程序不是很有利 对实时应用的支持是微弱的 Project:Linux的调度算法分析 2019/1/1 Linux OS Analysis

作业: Linux为什么要引入pidhash表? 在传统的UNIX系统中,创建子进程时会复制父进程的所有资源,代价比较高,现代UNIX系统中引入了哪几项技术来解决这个问题? Linux2.4中,名词解释: epoch 基本时间片 2019/1/1 Linux OS Analysis