一、Linux基础结构模型
Linux系统的组成分为4个部分:
1.内核:
管理硬件资源,并且将硬件资源虚拟成其他样子提供给上层所需要运行的应用程序。
2.Shell:
命令解释器,将用户输入命令传到内核
3.文件系统:
xfs,ext4,ext3,ext2,msdos,vfat,iso9660
4.应用程序
linux还可以分为用户态和内核态。
处于内核态的操作系统内核对于硬件有不受限制的使用权限,并且可以执行任何 CPU 指令以及访问任意的内存地址。
处于用户态进程没有能力直接操作硬件,也没有能力访问任意的内存地址空间。用户态进程只能通过操作系统内核提供的系统调用受限地使用硬件资源。并且用户态进程不能执行一些 CPU 特权指令。
其中内核是操作系统的核心,具有很多最基本功能,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。是最重要的部分。
二、进程管理
1、进程的定义
进程是由代码(text)、用户数据段(user segment)和系统数据段(system segment)(包含PCB)组成的一个动态实体
进程不同于程序,他与程序有以下的不同
(1)进程同程序的比较,程序是指令的有序集合,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
(2)程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。
(3)进程更能真实地描述并发,而程序不能
(4)进程是由PCB、程序段和数据段三部分组成的。进程具有创建其他进程的功能,而程序没有
2、进程的特性
(1)结构特征进程控制块(PCB)+程序段+相关的数据段=进程实体
(2)动态性——最基本特征进程:进程实体的一次执行过程,有生命周期。程序:程序是一组有序指令的集合,是静态的概念
(3)并发性多个进程实体同存于内存中,在一段时间并发运行;程序不能并发执行
(4)独立性进程实体是一个能独立运行、独立分配资源和独立接受调度的基本单位,而程序则不是。
(5)异步性进程按各自独立的、不可预知的速度向前推进
3、进程的状态
4、进程调度
进程调度的算法有:先到先服务算法、最短CPU运行期优先调度算法、优先级调度、 轮转法调度、多级队列调度、多级队列反馈调度等。
Linux的进程调度是基于优先级的调度
Linux的进程分为普通进程和实时进程,在基于优先级的算法下实时进程的优先级高于普通进程。
Linux中进程的优先级是动态的,调度程序周期性的调整他们的优先级,避免进程饥饿
Linux进程的策略有三种:
1、普通进程的时间片轮转算法
2、实时进程的先进先出算法
3、实时进程的时间片轮转算法
调度时机:
1、进程状态发生变化
2、当前进程时间片用完
3、进程从系统调用返回到用户态
4、中断处理后,进程返回到用户态
普通进程按照SCHED_OTHER调度策略进行进程调度。实时进程按照SCHED_FIFO或SCHED_RR策略进行调度。SCHED_FIFO是按先进先出方法选择下一个使用CPU的进程。SCHED_RR是实时进程的时间片轮转法策略(RoundRobin)。
三、中断和异常
中断(广义)会改变处理器执行指令的顺序,通常与CPU芯片内部或外部硬件电路产生的电信号相对应n中断——异步的:由硬件随机产生,在程序执行的任何时候可能出现n异常——同步的:在(特殊的或出错的)指令执行时由CPU控制单元产生我们用“中断信号”来通称这两种类型的中断。
中断的分类:
(1)可屏蔽中断:
I/O设备发出的所有中断请求(IRQ)都可以产生可屏蔽中断。
可屏蔽中断可以处于两种状态:屏蔽的(masked)和非屏蔽的(unmasked)
(2)非屏蔽中断:
只有几个特定的危急事件才引起非屏蔽中断。如硬件故障或是掉电
异常的分类:
(1)处理器探测异常:
由CPU执行指令时探测到一个反常条件时产生,如溢出、除0错等
(2)编程异常:
由编程者发出的特定请求产生,通常由int类指令触发通常叫做“软中断”例如系统调用。
系统调用作为一种特殊的中断,就是利⽤陷阱(trap)这种软件中断⽅式主动从⽤户态进⼊内核态的。
中断的处理过程:
- 确定中断向量。
- 利用中断向量在IDT中找到对应中断门,在中断门中得到段选择符从而可以从GDT中找到中断服务例程的段基址。
- 确定中断发生的特权级合法(linux只有内核态和用户态两种特权级,此步用来检查中断程序的特权是否低于引起中断的程序的特权,低优先级程序不能引起高优先级程序)
- 检查是否发生特权级变化(用户态陷入内核态,这时候需要设置内核的堆栈),如果发生读取当前程序的tss段(通过tr寄存器读取)来选择新特权级的ss和esp指针,然后保存旧的ss和esp指针。
- 若发生的是故障,用引起异常的指令地址修改cs和eip寄存器的值,以使得这条指令在异常处理结束后能被再次执行。
- 在栈中保存eflags、cs和eip的内容。
- 如果异常产生一个硬件出错码,则将它保存在栈中。
- 装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。这对寄存器值给出中断或者异常处理程序的第一条指定的逻辑地址
四、文件系统
文件系统,就是操作系统中实现文件统一管理的一组软件、被管理的文件以及为实施文件管理所需要的一些数据结构的总称。
第一层为文件系统接口层,如open、write、close等系统调用接口。
第二层为VFS (Virtual File System)接口层。该层有两个接口:
(1)与用户的接口;
(2)与特定文件系统的接口。
VFS与用户的接口将所有对文件的操作定向到相应的特定文件系统函数上。VFS与特定文件系统的接口主要是通过vfs-operations来实现的。
第三层是具体文件系统层,提供具体文件系统的结构和实现,包括网络文件系统,如NFS (network file system)。
虚拟文件系统是 Linux 内核中的一个软件层,用于给用户空间的程序提供文件系统接口;它提供了内核中的一个抽象功能,允许不同的文件系统共存。系统中所有的文件系统不但依赖 VFS 共存,而且也依靠 VFS 协同工作。为了能够支持各种实际文件系统,VFS 定义了所有文件系统都支持的基本的、概念上的接口和数据 结构;同时实际文件系统也提供 VFS 所期望的抽象接口和数据结构,将自身的诸如文件、目录等概念在形式 上与VFS的定义保持一致。一个实际的文件系统想要被 Linux 支持,就必须提供一个符合VFS标准 的接口,才能与 VFS 协同工作。实际文件系统在统一的接口和数据结构下隐藏了具体的实现细节,所以在VFS 层和内核的其他部分看来,所有文件系统都是相同的。
1、文件的打开步骤:
(1)应用程序对open ( )的调用将引起内核调用服务例程sys_open ( )函数,该函数接收的参数为:要打开文件的路径名和访问模式等;
(2)该系统调用成功后将返回一个文件描述符,也就是文件对象指针数组的一个索引;
(3)系统调用不成功时返回-1。
2、文件关闭步骤:
(1)用户程序通过close ( )系统调用关闭打开的文件,该函数接收的参数为要关闭文件的文件描述符。
(2)内核服务例程为sys_close ( )函数。
3、读文件大概流程如下:
(1)进程调用库函数向内核发起读文件请求;
(2)内核通过检查进程的文件描述符定位到虚拟文件系统的已打开文件列表表项;
(3)调用该文件可用的系统调用函数read()。read()函数通过文件表项链接到目录项模块,根据传入的文件路径,在目录项模块中检索,找到该文件的inode;
(4)在inode中,通过文件内容偏移量计算出要读取的页;
(5)通过inode找到文件对应的address_space;
(6)在address_space中访问该文件的页缓存树,查找对应的页缓存结点:
(7)如果页缓存命中,那么直接返回文件内容;
(8)如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页;重新进行第6步查找页缓存;
(9)文件内容读取成功。
五、举例子:
读一个文件:
-
进程调用库函数read向内核发起读文件请求
-
触发系统调用sys_read(),获得当前进程的控制块
-
系统调用read()会触发相应的VFS的read()函数
-
然后找到file结构,再找到fd数组,以fd为索引找到对应项,然后找到系统打开文件表
-
执行系统打开文件表里面的file operation里面的read
六、有关课程改进的建议
孟老师和李老师都讲的很棒,各有各的特色,在抢课的时候,差点没选到两位老师的课程,所有两位老师的课还是很受广大学生的喜爱,linux这门课还是需要一定的C基础和代码基础,对于小白前期有些吃力,希望这门课能够分配更多的课时。