1.进程管理
概述:进程是Linux进行资源分配和调度的基本单位,进程也被看做是程序的一次执行过程,当持久化在磁盘上的二进制代码被载入内存时,Linux操作系统为其分配了用户栈和内核栈,同时使用task_struct这种数据结构对进程进行描述,task_struct是Linux操作系统感知进程存在的数据结构,具体描述了进程号,进程状态,进程的调度策略和调度信息,进程打开文件表,进程链表,父子进程的关系等信息。Linux根据这个数据结构找到进程对应的用户栈和内核栈,并根据cs,ip,ss,sp,ebp等寄存器信息,执行这个进程。
进程的状态以及状态之间的切换(如下图所示)
需要注意的是,就绪态和运行态在系统中的状态都是TASK_RUNNING
,也就是说,在Linux内核中,当进程是TASK_RUNNING状态时,它是可运⾏的,也就是就绪态,是否在运⾏取决于它有没有获得CPU的控制权,也就是说这个进程有没有在CPU中实际执⾏。如果在CPU中实际执⾏着,进程状态就是运⾏态;如果被内核调度出去了,在等待队列⾥就是就绪态。
进程创建
linux提供了几个系统调用来创建和终止进程:
fork,vfork,clone来创建新进程(最终都通过__do_fork)
exec执行一个新程序
exit来终止进程
调度时机
进程状态发生变化时
当前进程时间片用完时
进程从系统调用返回到用户态时
中断处理后,进程返回到用户态时
进程的上下文切换(如下图所示)
2.系统调用
应用程序 代码调用系统调用( xyz ),该函数是一个包装系统调用的 库函数 ;
库函数 ( xyz )负责准备向内核传递的参数,并触发 软中断 以切换到内核;
CPU 被 软中断 打断后,执行 中断处理函数 ,即 系统调用处理函数 ( system_call);
系统调用处理函数 调用 系统调用服务例程 ( sys_xyz ),真正开始处理该系统调用。
3.中断管理
内核的一个主要功能就是处理硬件外设I/O,而cpu的速度比外设快很多,如果使用轮询方式与外设交互,显然会浪费许多cpu的资源,所以需要操作系统支持中断。
中断和异常的硬件处理
进入中断/异常
当cpu执行完一条指令后,会检查是否发生了中断或者异常。如果发生了中断或异常,则执行下列操作:
- 确定与中断或者异常关联的向量i(0~255)
- 读idtr寄存器指向的IDT表中的第i项
- 从gdtr寄存器获得GDT的基地址,并在GDT中查找,以读取IDT表项中的段选择符所标识的段描述符
- 比较程序的权限,确定中断是由授权的发生源发出
- 检查是否发生了特权级的变化,如果是由用户态进入内核态,需要进程堆栈切换
- 若发生的是故障,用引起异常的指令地址修改cs和eip寄存器的值,以使得这条指令在异常处理结束后能被再次执行
- 在栈中保存eflags、cs和eip的内容
- 如果异常产生一个硬件出错码,则将它保存在栈中
- 装载cs和eip寄存器,其值分别是IDT表中第i项描述符的段选择符和偏移量字段。
此时,进程的内核堆栈如下图所示:
中断服务程序占用的是被中断进程的内核栈,因此在中断服务程序正式执行之前,还需要将硬件没有自动入栈的一些通用寄存器进行手动入栈,其顺序与pt_regs
结构相对应。
从中断/异常返回
中断/异常处理完后,相应的处理程序会执行一条iret
汇编指令,这条汇编指令让CPU控制单元做如下事情:
- 用保存在栈中的值装载cs、eip和eflags寄存器。如果一个硬件出错码曾被压入栈中,那么弹出这个硬件出错码
- 检查处理程序的特权级是否等于cs中最低两位的值(这意味着进程在被中断的时候是运行在内核态还是用户态)。若是,iret终止执行;否则,转入3
- 从栈中装载ss和esp寄存器。这步意味着返回到与旧特权级相关的栈
- 检查ds、es、fs和gs段寄存器的内容,如果其中一个寄存器包含的选择符是一个段描述符,并且特权级比当前特权级高,则清除相应的寄存器。这么做是防止怀有恶意的用户程序利用这些寄存器访问内核空
中断处理
主要流程
- 在内核态堆栈保存IRQ的值和寄存器的内容
- 为正在给IRQ线服务的PIC发送一个应答,这将允许PIC进一步发出中断
- 调用
do_IRQ()
,执行共享这个IRQ的所有设备的中断服务例程 - 跳到ret_from_intr()的地址后中断跳出
do_IRQ()
根据中断向量号i找到对应的中断描述符,将注册到本中断的各个设备的irqaction都执行一遍。
4.文件系统
VFS
VFS是一个软件层,用来处理与Unix标准文件系统相关的所有系统调用,能为各种文件系统提供一个通用的、统一的接口。对于用户而言,不再需要自己针对每个不同的文件系统执行不同的操作命令,只需要用统一的open eadwrite等操作。
VFS与具体文件系统的关系如下图所示,它向上提供统一的接口,向下兼容各种不同的文件系统。
文件系统的结构包括在磁盘上的结构和在内存中的结构。磁盘上包括引导控制块、盘控制块、目录结构、FCB。在内存中包括:
- 系统打开文件表:包含每个已打开文件的FCB的副本,以及其他信息。
- 进程打开文件表:包含一个指向系统打开文件表相应项的指针,以及其他信息。
示例一:读文件:
-
进程调用库函数read向内核发起读文件请求
-
触发系统调用sys_read(),获得当前进程的控制块
-
系统调用read()会触发相应的VFS的read()函数
-
然后找到file结构,再找到fd数组,以fd为索引找到对应项,然后找到系统打开文件表
-
执行系统打开文件表里面的file operation里面的read
此处有个点需要注意:为什么read之前要先open呢?因为这个系统打开文件表是open创建的。