课程总结报告

请您根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。,

谈谈您对课程的心得体会,改进建议等。

产出要求是发表一篇博客文章,长度不限,只谈自己的思考,严禁引用任何资料造成文章虚长。

精简的Linux系统概念模型

Linux的系统层次结构包括用户空间和内核空间,用户空间是操作系统执行的地方,包含了用户应用程序、C函数库等;内核空间包括,系统调用,内核,以及与平台架构相关的代码。Linux内核的主要组件包括系统调用接口、进程管理、内存管理、文件系统、网络堆栈、设备驱动程序和硬件架构代码。

操作系统的从用户空间转换到内核空间是通过系统调用完成的,系统调用属于一种特殊的中断,系统调用同时伴随着中断上下文切换。

下面给出Linux系统的一般执行过程:

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

  2. 发生中断(包括异常、系统调用等), CPU将当前 CPU 上下文压入进程 X 的内核堆栈,并且加载当前进程内核堆栈相关信息,跳转到中断处理程序,即中断执行路径的起点。

  3. SAVE_ALL ,保存现场,进行中断上下文切换,具体过程如下:

    1. swapgs 指令保存现场,相当于 CPU 通过 swapgs 指令给当前 CPU 寄存器状态做了⼀个快照。
    2. rsp point to kernel stack ,加载当前进程内核堆栈栈顶地址到 RSP 寄存器。快速系统调用是由系统调用入⼝处的汇编代码实现用户堆栈和内核堆栈的切换。
    3. save cs:rip/ss:rsp/rflags :将当前 CPU 关键上下文压入进程 X 的内核堆栈,快速系统调用是由系统调用入⼝处的汇编代码实现的。

    此时完成了中断上下文切换,即从进程 X 的用户态到进程 X 的内核态。

  4. 中断处理过程中或中断返回前调用了 schedule 函数,其中完成了进程调度算法选择 next 进程、进程地址空间切换、以及switch_to 关键的进程上下文切换等。

  5. switch_to 调用了 __switch_to_asm 汇编代码做了关键的进程上下文切换。将当前进程 X 的内核堆栈切换到进程调度算法选出来的 next 进程Y的内核堆栈,并完成了进程上下Y文所需的指令指针寄存器状态切换。之后开始运行进程 Y 。

  6. 中断上下文恢复。

  7. 完成中断上下文恢复最后一步: iret - pop cs:rip/ss:rsp/rflags ,从 Y 进程的内核堆栈中弹出( 3 )中对应的压栈内容。此时完成了中断上下文的切换,即从进程 Y 的内核态返回到进程 Y 的用户态。

  8. 继续运行用户态进程 Y 。

中断管理

内核的一个功能是处理硬件外设io,但是处理器速度一般远远高于外设,内核必须先处理其他任务,只有当外设真正完成了准备好了时CPU才转过来处理外设io,中断就是其中一种io方式。

中断信号实际上改变了处理器执行指令的顺序,异步的中断信号被称为中断,由硬件随机产生,在程序执行的任何时候可能出现;同步的中断信号被称为异常,在特殊的或出错的指令执行时由CPU控制单元产生。

中断信号提供了一种特殊的方式,使得CPU转去运行正常程序之外的代码,比如一个外设采集到一些数据,发出一个中断信号,CPU必须立刻响应这个信号,否则数据可能丢失。当一个中断信号到达时,CPU必须停止它当前正在做的事,并且切换到一个新的活动。为了做到这这一点,在进程的内核态堆栈保存程序计数器的当前值(即eip和cs寄存器)以便处理完中断的时候能正确返回到中断点,并把与中断信号相关的一个地址放入进程序计数器,从而进入中断的处理。

内核的目标就是让中断尽可能快的处理完,尽其所能把更多的处理向后推迟。所以Linux系统的中断系统允许不同类型中断的嵌套发生,这样能使更多的I/O设备处于忙状态。不过,尽管内核在处理一个中断时可以接受一个新的中断,但在内核代码中还在存在一些临界区,在临界区中,中断必须被禁止。

中断处理程序本身并不是一个进程,而是一个内核控制路径,代表了中断发生时症状运行的进程执行,内核控制路径比一个正常的进程要更轻量,只包含有限的几个寄存器,建立和终止内存上下文需要的时候很少。

内核启动中断前,必须初始化IDT,然后把IDT的基地址装载到idtr寄存器中,int指令允许用户进程发出一个中断信号,其值可以是0-255的任意一个向量。

中断处理的基本过程是:

  1. 在内核态堆栈保存IRQ的值和寄存器的内容
  2. 为正在给IRQ线服务的PIC发送一个应答,这将允许PIC进一步发出中断
  3. 执行共享这个IRQ的所有设备的中断服务例程
  4. 跳到ret_from_intr()的地址后中断跳出

进程管理

Linux是一个多任务多用户操作系统,一个任务就是一个进程。每一个进程都具有一定的功能和权限,它们都运行在各自独立的虚拟地址空间。在Linux中,进程是系统资源分配的基本单位,也是使用CPU运行的基本调度单位。存放在磁盘上的可执行文件的代码和数据的集合称为可执行映象。当一个可执行映像装入系统中运行时,它就形成了一个进程。

对于操作系统来说,进程管理最主要的是进程的调度。

为了进程的调度,进程本身存在几种不同的状态,不同状态之间能够相互转换:

  • 运行态:进程正在使用CPU运行的状态。

  • 可运行态:进程已分配到除CPU外所需要的其它资源,等待系统把CPU分配给它之后即可投入运行。

  • 等待态:又称睡眠态,它是进程正在等待某个事件或某个资源时所处的状态。

  • 暂停态:进程需要接受某种特殊处理而暂时停止运行所处的状态。

  • 僵死态:进程的运行已经结束,但它的任务结构体仍在系统中。

当一个进程被创建时,系统就为该进程建立一个task_struct任务结构体。当进程运行结束时,系统撤消该进程的任务结构体。进程的任务结构体是进程存在的唯一标志。进程的任务结构体为内核管理进程,提供了内核所需了解的进程信息。Task_struct结构的描述包括:进程标识、进程状态(State)、进程调度信息和策略、进程通信有关的信息(IPC)、进程链接信息(Links)、时间和定时器信息(Times and Timers)、文件系统信息(Files System)、处理器相关的上下文信息。

为了控制进程的执行,内核必须有能力挂起正在 CPU 上运行的进程,并恢复执行以前挂起的某个进程。这种行为被称为进程切换。进程的切换就是变更进程上下文,基本步骤如下:

  1. 切换页全局目录( CR3 )以安装⼀个新的地址空间,这样不同进程的虚拟地址如 0x8048400 ( 32 位 x86 )就会经过不同的页表转换为不同的物理地址。
  2. 切换内核态堆栈和进程的 CPU 上下文,因为进程的 CPU 上下文提供了内核执行新进程所需要的所有信息,包含所有 CPU 寄存器状态。

文件系统

对大多数用户来说,文件系统是操作系统中最直接可见的部分。计算机的重要作用之一就是能快速处理大量信息,从而,信息的组织、存取和保管就成为一个极为重要的内容。文件系统是计算机组织、存取和保存信息的重要手段。文件系统,就是操作系统中实现文件统一管理的一组软件、被管理的文件以及为实施文件管理所需要的一些数据结构的总称。要实现操作系统对其它各种不同文件系统的支持,就要将对各种不同文件系统的操作和管理纳入到一个统一的框架中。对用户程序隐去各种不同文件系统的实现细节,为用户程序提供一个统一的、抽象的、虚拟的文件系统界面,这就是所谓的虚拟文件系统。通常,虚拟文件系统分为三个层次:

  • 第一层为文件系统接口层,如open、write、close等系统调用接口。
  • 第二层为VFS (Virtual File System)接口层。该层有两个接口:一个是与用户的接口;一个是与特定文件系统的接口。VFS与用户的接口将所有对文件的操作定向到相应的特定文件系统函数上。VFS与特定文件系统的接口主要是通过vfs-operations来实现的。
  • 第三层是具体文件系统层,提供具体文件系统的结构和实现,包括网络文件系统,如NFS (network file system)。

心得体会

Linux内核本身非常复杂丰富,令人望而生畏,在这门课程的学习中,老师深入浅出地带我们对Linux内核有了初步的把握,对Linux内核运行建立起了一定的模型,并且能够从底层汇编的角度对Linux内核进行一定的了解,感谢两位老师的讲解,我从这门课程中有了很多收获。

posted @ 2020-07-09 11:47  Litosty  阅读(201)  评论(0编辑  收藏  举报