操作系统——多进程与进程调度
实验目的:
多进程的实现机理与进程调度
实验内容:
1. 多进程问题,如何扩展单进程到多进程,如何扩展中断支持多进程?
2. 如何实现系统调用
3. 进程调度问题,弄清楚实现调度的基本思路
实验环境:
VMware + Ubuntu32位
实验步骤:
1.多进程问题,如何扩展单进程到多进程,如何扩展中断支持多进程?
1)进程体
首先需要不止一个进程体,所以先实现两个不同的进程体。
2)相关变量和宏
需要实现一个进程的运行需要4个变量&宏:进程表,进程体,GDT,TSS。
与之前单进程的进程初始化步骤完全相同,但我们为了方便,构造一个循环来进行初始化步骤,使得以后每多一个进程只需要添加一次循环即可。
3)进程表与初始化
在定义了以上结构体与宏定义之后,即可以开始初始化进程。
可以看到其实和上一次实验区别不大,也就是加了个循环…
4)LDT
算法与单进程类似,只是使用了一个循环来完成多进程的LDT填充问题。
5)中断处理程序
在单进程中我们的中断处理程序有两个任务,一个是打印字符,一个是从进程表中读取或写入寄存器值,以此恢复或保存进程运行状态。多进程同理,但是别忘了加一个进程切换步骤:
每当中断到来,将p_proc_ready加一,即为指向进程表的下一个表项。当p_proc_ready指向进程表最后一项时,让他指向进程表第一项。
调试结果如下:
2.如何实现系统调用
既然是系统调用,就是用户与操作系统交互的过程,所以需要告诉操作系统我现在要跟你交互什么,用中断就是一个不错的选择。
首先,将要向操作系统提出的问题,保存在eax寄存器中。
保存了问题之后,我们需要来写一个中断处理,也就是上图中的int INT_VECTOR_SYS_CALL。
init_idt_desc(INT_VECTOR_SYS_CALL, DA_386IGate,
sys_call, PRIVILEGE_USER);
其实和我们之前使用的hwint有一点像,hwint是调用irq_table[ ],我们这里是调用sys_call_table[eax]。当然别忘了初始化sys_call_table[ ]。在这里我们让这个数组指针中的一个指针指向我们的函数sys_get_ticks。
终于我们基本完成了初始化,下面修改一下进程。
到这一步,我们只是测试一下是否能成功中断。这个系统调用的实际功能是打印出时钟中断的数量,所以我们还需要完善。
既然是要计算时钟中断的数量,时钟中断处理程序就应该需要修改。
还是比较清晰的,来一次中断就加一呗。
然后修改sys_get_ticks()和进程Test:
结果如下:
A后面紧跟的个数表达的是这个A之前出现的#个数,也就是时钟中断的个数不是吗。
既然是对时钟中断进行操作的系统调用,我们应该发挥它“时钟”的特性,毕竟我们之前的delay函数就只是用了个循环…所以我们可以写一个计时器的系统调用。
结果如下:
3. 进程调度问题,弄清楚实现调度的基本思路
之前我们实现了基于时钟中断的delay函数,如果不同的进程执行之前delay不同时长,那我们就可以看成是给予进程不同的优先级。于是,我们选择在进程表中添加优先级的标志,也就是一个倒计时的数。
Priority为记录该进程优先级的变量,它是不变的。
Ticks为记录该进程某时刻倒计时的数,它的初始值为priority,并逐渐递减到0。
进程调度我们使用函数schedule来实现:
由于每一个进程的priority都不同,而ticks的初始值就是priority的值,所以在进程运行时,ticks值递减。当所有进程的ticks值都降到0时,全部ticks重新设置为该进程对应的priority的值,并继续递减。这样一来就实现了优先级的定义和进程调度。
此时我们的中断处理程序如下所示:
调试结果:
本次实验需要解决的问题:
1.在单进程的基础上扩展实现多进程要考虑哪些问题?
1)需要多个进程体
2)进程表与进程表初始化(变量与宏定义)
3)LDT
4)中断处理程序
2.画出以下关键技术的流程图:
– 初始化多进程控制块的过程、扩展初始化LDT和TSS
LDT与GDT的关系:
流程图:
3.如何修改时钟中断来支持多进程管理,画出新的流程图。
4.系统调用的基本框架是如何的,应该包含哪些基本功能,画出流程图。
5.如何操控可编程计数器?
根据不同硬件决定的两次时钟中断的间隔,来决定经过多少次时钟中断后,计数器计数。
6.进程调度的框架是怎样的?优先级调度如何实现?
进程调度的原理如上图,优先级则为进程表中的priority的值。priority越大,进程能分得的运行时间越多,也就意味着优先级越高。
7.动手做:修改例子程序的调度算法,模拟实现一个多级反馈队列调度算法,并用其尝试调度5-8个任务,输出性能评价信息。
1)创建5个任务。
打印了很多的空格,为了清屏。。。
2)初始化队列,修改进程表
3)调度算法
4)调试结果
8. 思考题:从用户态进程读和写内核段的数据,看能否成功,是否会触发保护,并解释原因。
1)可以读取内核段的数据
2)可以写内核段的数据