课程学习总结报告
要求:根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。并谈谈您对课程的心得体会,改进建议等。
一、Linux系统概念模型
Linux系统主要由Linux内核和其他外部程序组成,其主要结构如下图所示:

从上图可见,已学习的内核的工作主要有:进程管理、内存管理、文件系统、驱动管理等。用户通过系统调用,申请系统的内核服务。下面根据学习的时间顺序分别归纳这些知识点:
1、进程管理
首先我们要知道,Linux是一个多任务多用户操作系统, 一个任务(task)就是一个进程(process)。每一个进程都具有一定的功能和权限,它们都运行在各自独立的虚拟地址空间。 它们是系统资源分配的基本单位,也是使用CPU运行的基本调度单位。那么,进程是什么呢?存放在磁盘上的可执行文件的代码和数据的集合称为可执行映象。当一个可执行映像装入系统中运行时,它就形成了一 个进程。而为了使系统有效的管理进程,当一个进程被创建时,系统就为该进程建立一个task_struct任务结构体,即:进程控制块(PCB),它容纳了一个进程的所有信息,是进程存在的唯一标志,也是系统实现进程调度的主要依据。当进程运行结束时,系统撤消该进程的任务结构体,其结构如下:

通常情况下,由于CPU的计算资源是有限的,某一时刻只能处理一个进程,故处理多个进程需要进行进程调度,进程调度下进程的状态如下所示:

⚪ 进程切换主要有以下两步组成:①切换页全局目录以安装一个新的地址空间;②切换内核态堆栈和硬件上下文。其中,硬件上下文提供了内核执行新进程所需要的所有信息,包括CPU寄存器。每个进程可以有自己的地址空间,但只能共享CPU的寄存器。进程恢复执行前必须装入寄存器的数据包括:通用寄存器的值以及一些系统寄存器。我们通过switch_to宏执行进程切换,schedule()函数调用这个宏来调度一个新的进程在CPU上运行。
⚪ Linux提供了几个系统调用来创建和终止进程,以及执行新程序 :① Fork,vfork和clone系统调用创建新进程;② exec系统调用执行一个新程序;③ exit系统调用终止进程。
⚪ 进程调度共有两种类型:①非剥夺方式:分派程序把CPU分配给某进程后便让它一直运行下去,直到进程完成或发生某事件而阻塞,才把CPU分配给另一个进程。②剥夺方式:当一个进程正在运行时,系统可以基于某种原则,剥夺已分配给它的CPU,将之分配给其它进程。③剥夺原则有:优先权原则、短进程、优先原则、 时间片原则等。
⚪ 进程调度的时机有:①进程状态发生变化时;②当前进程时间片用完时;③进程从系统调用返回到用户态时;④中断处理后,进程返回到用户态时。
2、中断和异常
首先我们要弄清这两者的区别,中断是异步的,由硬件随机产生,在程序执行的任何时候可能出现;异常是同步的,在指令执行时由CPU产生,二者统称为“中断信号”。当一个中断信号到达时,CPU必须停止它当前正在做的事,并且切换到一个新的活动。该操作的步骤是:在进程的内核态堆栈,保存程序计数器的当前值(eip和cs寄存器)以便处理完中断的时候能返回到中断点,并把中断信号相关的地址放入程序计数器,从而进入中断的处理。
这里需要讨论一下中断上下文,不同于进程上下文,中断或异常处理程序执行的代码不是一个进程而是一个内核控制路径,代表了中断发生时正在运行的进程执行。作为一个进程的内核控制路径,中断上下文只包含了几个寄存器,建立和终止这个上下文所需要的时间很少。
⚪ 中断可分为:① 可屏蔽中断:I/O设备发出的所有中断请求(IRQ)都可能产生可屏蔽中断;② 非屏蔽中断:只有特殊的紧急情况才引起非屏蔽中断。如硬件故障或是掉电。
⚪ 异常可分为:① 处理器异常:由CPU执行指令时出现反常条件时产生,如溢出、除0等;② 编程异常:又叫做“软中断” ,如系统调用。而根据内核堆栈中的eip的值可以进一步将异常分为:故障,处理完指令异常后,它会被重新执行,如缺页异常。此时eip存储故障指令的地址;陷阱,即系统调用,eip存储随后执行指令的地址;异常中止,此时eip值无效,应强制终止进程。
⚪ 当发生了一个中断或异常,CPU进行如下操作:
① 确定与中断或者异常关联的向量i;② 读idtr寄存器指向的IDT表中的第i项;③ 从gdtr寄存器获得GDT的基地址,之后在GDT中查找被IDT表项中段选择符所标识的段描述符;④ 确定中断或异常的权限,即中断处理程序的权限不能低于引起中断的程序的权限,它们分别在GDT表项中的DPL和CS寄存器中的 CPL;若是编程异常,还需比较CPL与对应IDT表项中的DPL;⑤ 检查特权级是否变化,即用户态有没有陷入内核态。 若是,则控制单元必须使用与新的特权级相关的堆栈。⑥ 若是故障,用异常指令地址修改cs和eip寄存器,使得该指令在异常处理后能再次执行;⑦ 在栈中保存eflags、cs和eip的内容;⑧将IDT表中第i项的段选择符和偏移量装入cs和eip寄存器,它既是中断或者异常处理程序的首条逻辑地址。
⚪ 中断/异常处理完后会执行iret指令,CPU进行如下操作:
① 将栈中的值送入cs、eip和eflags寄存器,若之前有硬件出错码被压栈则将其弹出。②检查程序的权限是否为cs中最低两位的值,即进程被中断时是运行在内核态还是用户态。若是,iret终止执行。③从栈中弹出ss和esp寄存器,即返回到与旧特权级相关的栈。④检查段寄存器,若有寄存器存储的选择符为段描述符,且特权级比当前特权级高,则清空该寄存器,以防止用户程序利用该寄存器访问内核空间。
3、文件系统
文件系统,就是操作系统中实现文件管理的软件、文件以及数据结构的总称,它的结构如下图所示:

它使用按名存取,用户给出文件名就能存取在外存空间的文件,而不必关心文件的物理地址。实现文件名到物理地址映射的是检索文件目录。 系统为每个文件设置一个描述性数据结构:文件控制块FCB,文件目录就是文件控制块的有序集合。FCB是文件存在的标志,它记录了系统管理文件所需要的全部信息,包括: 文件名、文件号、用户名;文件的物理位置、文件长度;记录大小、文件类型、文件属性;共享说明;文件逻辑结构、文件物理结构;建立文件的日期和时间、最后访问日期和时间、最后修改日期和时间;保存期限等。
⚪ 文件的打开与关闭:① 打开文件是在进程与文件之间建立连接,由文件打开的描述符唯一标识,它是文件对象指针数组的一个索引。② 应用程序使用open()系统调用,调用内核服务例程sys_open()函数,参数为:打开文件的路径名和访问模式等,成功则返回一个文件描述符,不成功则返回-1。③ 应用程序通过close()系统调用,调用内核服务例程sys_close()函数,参数为要关闭文件的文件描述符,成功则关闭文件。
⚪ 文件的读/写:① 读/写文件的进程通过系统调用read()和write()完成访问目标文件的打开文件描述符。② read()和write()分别调用sys_read()和sys_write()内核服务例程。参数都为:文件描述符、数据的内存缓冲区地址、应传送的字节数。read()把数据从文件传送到缓冲区,write()正好相反。③ 若成功,二者都返回传送的字节数,并将其与文件指针相加来更新文件指针。若失败,则返回错误信号。④ 读/写操作总是发生在当前文件指针指向的文件偏移量处,即文件对象的f_pos域。
⚪ 虚拟文件系统:① Linux引入VFS,为各类文件系统提供一个统一的操作界面和应用编程接口。方法是使用一个支持所有文件系统的通用文件模型。② 通用文件模型有下列对象类型组成,超级块对象:存放文件系统相关信息,例如文件系统控制块;索引节点对象:存放文件控制块;文件对象:存放打开文件和进程之间交互的信息;目录项对象:存放目录项与文件的链接信息。③ 每个主要对象都包含一个操作对象,描述了内核对主要对象可以使用的方法。
二、以执行ping命令为例,类比Linux系统执行命令的流程
①检查执行的是否是绝对路径执行;②检查ping命令是否存在别名;③检查ping命令是内部命令还是外部命令;④如果是内部命令直接执行;⑤如果是外部命令,检查ping命令是否有缓存,如果没有,查找PATH变量;⑥检查PATH路径直到查找到该命令然后执行;⑦如果没有找到该命令则返回错误。
三、心得体会
通过对《Linux操作系统分析》这个课程几个月的学习,我了解了Linux系统的基本构成和运作方式,通过学习Linux每个部分的构成、作用和相互配合,使我对Linux系统有了一个系统的理解,同时让我对计算机的认识又深入了一层,这对以后各种计算机技术的学习无疑提供了巨大的帮助。两位老师在疫情期间依然保持了孜孜不倦、一丝不苟的教学风格,着实令人敬佩。祝这门课越办越好!

浙公网安备 33010602011771号