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


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

    黄韧(原创作品转载请注明出处)

    《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

    一、知识概要

    1. Linux中进程调度的基本概念与相关知识
    2. schedule函数如何实现进程调度
    3. Linux进程的执行过程(一般情况与特殊情况)
    4. 宏观描述Linux系统执行

    二、学习笔记

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

    进程进度与进程调度的时机分析

    1.不同类型的进程有不同的调度需求。

    2.第一种分类:

    • I/O-bound   频繁的进行I/O;通常会花费很多时间等待I/O操作的完成。
    • CPU-bound  计算密集型;需要大量的CPU时间进行运算。

    第二种分类:

    • 批处理进程 
    • 实时进程
    • 交互式进程  shell

    3.什么是调度策略?

    是一组规则,他们决定什么时候以怎样的方式选择一个新进程运行。

    4.Linux的进程根据优先级排队

    5.Linux进程的优先级是动态的

    6.内核中的调度算法相关代码使用了类似OOD中的策略模式。将调度算法与其他部分耦合了。

    7.进程调度的时机:schedule()函数实现调度。

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

    用户态进程只能被动调度。

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

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

    • 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换;

    • 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行;

    • 进程上下文包含了进程执行需要的所有信息

      • 用户地址空间: 包括程序代码,数据,用户堆栈等

      • 控制信息 :进程描述符,内核堆栈等

      • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)

    • 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系统的一般执行过程

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

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

    1.正在运行的用户态进程X

    2.发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).

    3.SAVE_ALL //保存现场

    4.中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换

    5.标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)

    6.restore_all //恢复现场

    7.iret - pop cs:eip/ss:esp/eflags from kernel stack

    8.继续运行用户态进程Y2

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

    我们一旦抽象过的东西,都不一定是准确的,还有几种特殊情况:

    • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
    • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
    • 创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;
    • 加载一个新的可执行程序后返回到用户态的情况,如execve;

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

    Linux操作系统架构概览

    1.操作系统的基本概念

    2.操作系统的目的

    3.典型操作系统架构

    最简单也是最复杂的操作——执行ls操作

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

    1.站在CPU执行指令的角度

    2.从内存的角度来看

    三、课后作业

    理解进程调度时机跟踪分析进程调度与进程切换的过程

    1.理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确; 

               见(一)进程切换的关键代码switch_to分析 进程上下文切换相关代码分析部分

    2.使用gdb跟踪分析一个schedule()函数 ,验证您对Linux系统进程调度与进程切换过程的理解;推荐在实验楼Linux虚拟机环境下完成实验。 

    (1)开启qemu以及gdb:

    (2)设置断点:

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

    (4)用list查看代码

    (5)单步执行发现__schedule()

    (6)进入函数:

    (6)继续单步执行直到发现pick_nexi_task():

    (7)继续单步执行,直到发现context_switch:

    (8)无法进入函数内部。所以设置了一个新的断点

    (9)之后继续执行,可以进入context_switch()函数并发现了switch_to()和__switch_to()

    (10)完成跟踪。

    3.特别关注并仔细分析switch_to中的汇编代码,理解进程上下文的切换机制,以及与中断上下文切换的关系;

               见(一)进程切换的关键代码switch_to分析 进程上下文切换相关代码分析部分 之汇编代码分析

  • 相关阅读:
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (四) 自动化部署
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (三) 服务观测
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (二) 部署微服务程序
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (一) 部署 Nacos
    C++知识点
    libmkl 学习笔记
    基于tesseract-OCR进行中文识别
    poco编译与运行
    Linux下的I/O复用与epoll详解(转载)
    高并发网络编程之epoll详解(转载)
  • 原文地址:https://www.cnblogs.com/huangbobo/p/5390340.html
Copyright © 2020-2023  润新知