操作系统的一个核心功能就是进程的调度,进程是什么呢?很多书上已经给出了标准的解释,我自己理解的是一个特定环境下的函数,进程可以是用户的任务,也可以是系统的某个服务程序。
进程的环境主要有:通用寄存器、控制寄存器、一块私有的内存与代码、对应的GDT、LDT、TR、TSS、中断环境、内存页表。
GDT:(全局描述符)
空描述符 ;必须的。
代码描述符;前8M
数据描述符;4G
堆栈描述符;内核用。
TSS描述符;
显存描述符;
进程用LDT描述符;含调用门描述符
LDT:(进程描述符、含调用门描述符)
进程代码段;
进程数据段;
进程堆栈段;
进程用1级堆栈段;为系统调用准备,属于进程。
系统调用门0;特权级为1级,从此以下为静态,不改变。
系统调用门1;特权级为1级
系统调用门n;特权级为1级
……
进程表:
进程ID号
进程名称
进程特权权
进程优先级
进程LDT
上个进程指针
下个进程指针;这两指针是在内核页表下的内存指针,指向进程表开始处。
当前进程状态
进程内存页目录表
进程状态表(通用寄存器组、段寄存器组、标志寄存器等)
进程窗口指针
进程代码、数据区
进程内存页表
TSS:
目前使用进程表进行切换,只使用ss0、esp0、ss1、esp1 其他的不用。
显存:
只有1级以上权限,用户不得支接读写。静态。
中断环境:
静态,调试环境为独立环境。
内存页表:
前8M为系统内核区,所有进程的内存页表不得占用,由内核进行维护。
进程页表切换,进程切换时,先将内存页表切换为内核页表,再取出进程页表,加载进程页表。
内核页表一般对应着物理内存。只有物理内存不够时,才会将不活动的进程数据保存到硬盘,进行映射,空出内存空间。
内存安排:0-FFFFF 内核,100000-1FFFFF 系统调用函数,200000-5FFFFF 内核页表,600000-7FFFFF 内存映射表
一个页目录项表指向4M内存空间,系统内核区占2个页目录项表。
系统0号进程:
消息分派与传递,用户进程的看护,有最优权限与资源。
当一个进程需要启动时:
1、取得进程属性,确定需要占用的内存数;
2、分配内存,修改内存页表;
3、使用进程的内存页表;
4、创建新的进程表,并修改相应数据;
5、修改LDT,以适应新的进程环境;
6、将进程代码读取到指定的内存;
7、重新加载LDT;
8、切换前准备,修改TSS,内核指针指向进程状态表底部;
9、切入进程;
进程切换时:
1、保存CS、EIP到程序状态表;(系统自动保存)
2、保存通用寄存器;pushad
3、切换至内核堆栈;
4、判断当前进程是否已用完时间片;未用完跳到8;
5、取下一个进程指针;
6、加载下一个进程的环境;(修改GDT、LDT、TSS)。
7、重新加载LDT、CR3、页表等。
8、修改TSS的SS0、ESP0,准备下次中断或系统调用使用。
9、返回进程。
中断时的进程进出与上面的进程切换差不多,少一个进程的转换过程,开头和结尾一样。
系统调用时,也是在0级权限中,这样就与中断有冲突了,所以Linux不用调用门,可能就是这个原因。因些我们要把系统调用的权限改为1级,这样就可以避免TSS中堆栈冲突。
当在系统调用过程中发生进程切换,0级堆栈中存放了调用返回的代码段与偏移,占用了进程状态表。