LINUX内核分析第八周学习总结

标签(空格分隔): 20135328陈都


陈都 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

一、进程切换的关键代码switch_to的分析

1.进程调度与进程调度的时机

  1. 不同类型的进程有不同的调度需求。
  2. 第一种分类:
    • I/O-bound 频繁的进行I/O;通常会花费很多时间等待I/O操作的完成。
    • CPU-bound 计算密集型;需要大量的CPU时间进行运算。
  3. 第二种分类:
    • 批处理进程,不必与用户交互,通常在后台运行,不必很快响应。主要用于编译程序,科学计算
    • 实时进程,需要经常与用户交互,所以要花很多时间等待用户输入操作,响应时间要快,平均延迟低于50~150ms。主要用于shell,文本编辑程序,图形应用程序
    • 交互式进程 shell,有实时需求,不应被低优先级的进程阻塞,响应时间要短要稳定。主要用于视频、音配、机械控制。

2.不同的进程要采取不同的进程调度策略

调度策略:是一组规则,它们决定什么时候以怎样的方式选择一个新进程运行
Linux中的调度是多种策略和调度算法的组合
  • Linux的调度基于分时和优先级策略:

    • 进程根据优先级(系统根据特定算法计算出来)排队;
    • 这个优先级的值表示如何适当分配CPU;
    • 调度程序会根据进程的运行周期动态调整优先级;
    • 比如nice等系统调用,可以手动调整优先级

调度策略本质上是一种算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已

常见的一些函数:

nice
getpriority/setpriority 设置优先级
sched_getschedduler/sched_setscheduler
sched_getparam/sched_setparam
sched_yield
sched_get_priority_min/sched_get_priority_max
sched_rr_get_interval

3.进程的调度时机

1.schedule函数实现调度

  • 目的:在运行队列中找到一个进程,把cpu分配给它
  • 方法:
    • 直接调用schedule()
    • 松散调用,根据need_resched标记

2.进程调度的时机

  • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();主动调度。
  • 用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。用户态进程只能被动调度。
  • 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程既可以主动调度,也可以被动调度;

内核线程是只有内核态没有用户态的特殊进程

4.进程上下文切换相关代码分析

  1. 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换。
  2. 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行。
  3. 进程上下文包含了进程执行需要的所有信息
    • 用户地址空间:包括程序代码,数据,用户堆栈等
    • 控制信息:进程描述符,内核堆栈等
    • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
  4. schedule()函数选择一个新的进程来运行,并调用context_ switch进行上下文的切换,这个宏调用switch_ to来进行关键上下文切换
    • next = pick_ next_ task(rq, prev);//进程调度算法都封装这个函数内部
    • context_ switch(rq, prev, next);//进程上下文切换
    • switch_ to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

schedule函数:

具体内容:

进程上下文切换:

切换准备:

切换寄存器状态和堆栈:

具体分析switch_to汇编:

  • 42:保存当前进程的flags
  • 43:把当前进程的堆栈基址压栈
  • 44:把当前的栈顶保存起来
  • 45:把下一进程栈顶放入esp寄存器 完成内核堆栈切换
  • 46:保存当前进程的eip,再恢复时用
  • 47:下一进程栈顶是起点。next_ip一般是$1f,对于新创建的子进程是ret_from_fork
  • 49: 通过寄存器传递参数
  • 50:认为是next进程开始了 46~49模糊地带


二、Linux系统的一般执行过程

  1. Linux系统的一般执行过程分析

    --

最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

  1. 正在运行的用户态进程X
  2. 发生中断——

save cs:eip/esp/eflags(current) to kernel stack

压入内核堆栈

load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).

把当前进程的内核堆栈的信息保存,和当前中断例程的起点加载

  1. SAVE_ALL //保存现场
  2. 中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
  3. 标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
  4. restore_all //恢复现场
  5. iret - pop cs:eip/ss:esp/eflags from kernel stack从内核堆栈中弹出y的相关信息
  6. 继续运行用户态进程Y

2.Linux系统执行过程中的几个特殊情况

  • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断的时候没有进程用户态和内核态的转换,cs不会变化;
  • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,也不需要从中断中返回,与最一般的情况相比更简略;
  • 创建子进程的系统调用在子进程中的执行起点(如ret_from_fork,上文中也已经提到过)及返回用户态;
  • 加载一个新的可执行程序后返回到用户态的情况,如execve,在新进程内部修改了中断保存的信息

3.内核与舞女

  1. 进程的地址空间一共有4G,其中0——3G是用户态可以访问,3G以上只有内核态可以访问
  2. 内核相当于出租车,可以为每一个“招手”的进程提供内核态到用户态的转换
  3. 没有进程需要“承载”的时候,内核进入idle0号进程进行“空转”。当用户进程有需求时,内核发生中断,帮助用户进程完成请求,然后再返回到用户进程。就好像Taxi将用户载了一圈之后又把用户放下来。
  4. 3G以上的部分就是这样的“出租车”,是所有进程共享的,在内核态部分切换的时候就比较容易
  5. 内核是各种中断处理程序和内核线程的集合。

三、Linux系统架构和执行过程概览

1.linux操作系统架构概览

操作系统的基本概念及目的

操作系统:计算机系统包含的一个基本的程序集合

目的:与硬件交互,为用户程序提供一个良好的执行环境

典型的Linux操作系统架构

2.最简单、最复杂的操作——执行ls命令

  • 在控制台输入ls命令
  • Shell程序分析输入参数,确定这是ls
  • 调用系统调用fork生成一个shell本身的拷贝
  • 调用exec系统调用将ls可执行文件装入内存
  • 从系统调用返回
  • Shell和ls都得到执行

3.从CPU和内存的角度来看Linux系统的执行

  • 执行gets()函数;
  • 执行系统调用,陷入内核;
  • 等待输入,CPU会调度其他进程执行,同时wait一个I/O中断;
  • 敲击ls,发I/O中断给CPU,中断处理程序进行现场保存、压栈等等;
  • 中断处理程序发现X进程在等待这个I/O(此时X已经变成阻塞态),处理程序将X设置为WAKE_UP;
  • 进程管理可能会把进程X设置为next进程,这样gets系统调用获得数据,再返回用户态堆栈
  • 从内存角度看,所有的物理地址都会被映射到3G以上的地址空间:因为这部分对所有进程来说都是共享的

四、实践部分

实践要求:

  1. 使用gdb跟踪分析一个schedule()函数 ,验证您对Linux系统进程调度与进程切换过程的理解
  2. 特别关注并仔细分析switch_to中的汇编代码,理解进程上下文的切换机制,以及与中断上下文切换的关系

实践过程:

  1. 启动内核,并进入调试状态

  2. 设置断点

  3. 按c继续,可以发现core.c里面调用了_schedule()

  4. 用list查看代码

  5. 设置switch_to断点

先找到switch_to的具体行再设置断点

  1. 单步执行直到发现pick_nexi_task()

  2. 继续单步执行,直到发现context_switch

  3. 进入context_switch()函数并发现了switch_to()

  4. 跟踪完成

五、小结

  • Linux调度的核心函数为schedule,schedule函数封装了内核调度的框架。
  • Linux内核中实现进程的切换主要通过保存进程相关的信息实现,这里需要注意进程切换中内核级进程的切换和用户态进程切换的不同。
  • 内核态可以直接调用schedule函数并不需要陷入中断这个过程。而用户态则需要陷入内核态才能实现进程的切换
  • schedule()函数实现进程调度,context_ switch完成进程上下文切换,switch_ to完成寄存器的切换。
  • 在调度时机方面,内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度。
  • 所谓进程的切换主要就是堆栈的切换,这是由宏操作switch_to()完成的

LINUX内核分析第八周学习总结的更多相关文章

  1. LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程

    LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...

  2. Linux 内核分析第八周学习笔记

    Linux 内核分析第八周学习笔记 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10 ...

  3. LINUX内核分析第八周学习总结:进程的切换和系统的一般执行过程

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

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

    实验作业:进程调度时机跟踪分析进程调度与进程切换的过程 20135313吴子怡.北京电子科技学院 [第一部分]理解Linux系统中进程调度的时机 1.Linux的调度程序是一个叫schedule()的 ...

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

    第八周 进程的切换和系统的一般执行过程 一.进程切换的关键代码switch_to分析 1.进程调度与进程调度的时机分析 (1)进程分类 第一种分类 I/O-bound:等待I/O CPU-bound: ...

  6. LINUX内核分析第七周学习总结:可执行程序的装载

    LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  7. LINUX内核分析第七周学习总结——可执行程序的装载

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

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

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

  9. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

随机推荐

  1. golang的json序列化问题

    首先看一段代码: package main import ( "encoding/json" "fmt" ) type Result struct { //st ...

  2. GUI_菜单练习

    package com.mywindow.test; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; ...

  3. File类_常见的方法(获取,创建与删除,判断,重命名)

    获取:  1.1获取文本名称  1.2获取文件路劲  1.3获取文件大小  1.4获取文件修改或创建时间 import java.io.File; import java.text.DateForma ...

  4. 习题 6 字符串(string)和文本

    虽然你已经在程序中写过字符串了,你还没学过它们的用处.在这章习题中我们将使用复杂的字符串来建立一系列的变量,从中你将学到它们的用途.首先我们解释一下字符串是什么 东西. 字符串通常是指你想要展示给别人 ...

  5. IOS - 执行时 (经常使用函数)

    能够通过NSObject的一些方法获取运行时信息或动态运行一些消息: /*Returns a Boolean value that indicates whether the receiving cl ...

  6. 转 spring配置文件

    spring配置文件   pom文件: <properties> <commons-lang.version>2.6</commons-lang.version> ...

  7. 通过JSP网页连接MySQL数据库,从MySQL数据库中读出一张表并显示在JSP网页中

    1.安装所需软件 ①安装java和tomcat,建立JSP网页最基础的软件②安装MySQL数据库(下载地址:https://www.mysql.com/)③安装Navicat Premium来查看数据 ...

  8. <<linux device driver,third edition>> Chapter 3:Char Drivers

    The Internal Representation of Device Numbers Within the kernel,the dev_t type(defined in linux/type ...

  9. Linux下DHCP服务安装配置

    简介 安装配置 一.简介 DHCP (Dynamic Host Configuration Protocol,动态主机管理协议)是一种基于UDP协议且仅限用于局域网的网络协议,主要用途是为局域网内部设 ...

  10. linux内存源码分析 - 页表的初始化

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 本文章中系统我们假设为x86下的32位系统,暂且不分析64位系统的页表结构. linux分页 linux下采用四 ...