操作系统lab2-chrt
内容与设计思想
在MINIX3中实现Earliest-Deadline-First近似实时调度功能:
- 提供设置进程执行期限的系统调度chrt (long deadline),用于将调用该系统调用的进程设为实时进程,其执行的期限为:从调用处开始deadline秒。
- 在内核进程表中需要增加一个条目,用于表示进程的实时属性;修改相关代码,新增一个系统调用chrt,用于设置其进程表中的实时属性。
- 修改proc.c和proc.h中相关的调度代码,实现最早deadline的用户进程相对于其它用户进程具有更高的优先级,从而被优先调度运行。
- 在用户程序中,可以在不同位置调用多次chrt系统调用,在未到deadline之前,调用chrt将会改变该程序的deadline。
- 未调用chrt的程序将以普通的用户进程(非实时进程)在系统中运行。
实验过程
应用层
- 在/usr/src/include/unistd.h 中添加chrt函数定义
- 在/usr/src/minix/lib/libc/sys/chrt.c中添加chrt函数实现。
此处修改deadline值,将当前时间戳+deadline,即进程结束的绝对时间作为新的deadline值向下传递,作为进程调度决策的参数。
- 在/usr/src/minix/lib/libc/sys中Makefile.inc文件添加chrt.c条目
服务层
- 在/usr/src/minix/servers/pm/proto.h中添加chrt函数定义
- 在/usr/src/minix/servers/pm/chrt.c中添加chrt函数实现,调用sys_chrt()。
- 在/usr/src/minix/include/minix/callnr.h中定义PM_CHRT编号。
- 在/usr/src/minix/servers/pm/Makefile中添加chrt.c条目。
- 在/usr/src/minix/servers/pm/table.c 中调用映射表。
- 在/usr/src/minix/include/minix/syslib.h 中添加sys_ chrt () 定义。
- 在/usr/src/minix/lib/libsys/sys_chrt.c 中添加sys_chrt () 实现。可参照该文件夹下的sys_fork文件,在实现中通过_kernel_call (调用号)向内核传递。
- 在/usr/src/minix/lib/libsys 中的Makefile中添加sys_chrt.c条目。
内核层
- 在/usr/src/minix/kernel/system.h中添加do_chrt函数定义。
- 在/usr/src/minix/kernel/system/do_chrt.c中添加do_chrt函数实现。
- 在/usr/src/minix/kernel/config.h 中添加USE_FORK。
- 在/usr/src/minix/kernel/system/ 中Makefile.inc文件添加do_chrt.c条目。
- 在/usr/src/minix/include/minix/com.h中定义SYS_CHRT编号。
- 在/usr/src/minix/kernel/system.c 中添加SYS_CHRT编号到do_chrt的映射。
- 在/usr/src/minix/commands/service/parse.c的system_tab中添加名称编号对。
进程调度
- 修改/usr/src/minix/kernel/proc.h在struct proc中添加p_deadline成员。
- 修改/usr/src/minix/kernel/proc.c中enqueue_head()和enqueue()函数,在实时进程入队时设置优先级为5。
- 修改/usr/src/minix/kernel/proc.c中pick_proc()函数,选择进程时遍历队列,优先选择最先中止运行的进程
测试
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void proc(int id);
int main(void) {
for (int i = 0; i < 3; i++) {
if (fork() == 0) {
proc(i + 1);
}
}
return 0;
}
void proc(int id) {
int loop;
switch(id) {
case 1:
chrt(20);
printf("proc1 set success\n");
sleep(1);
break;
case 2:
chrt(15);
printf("proc2 set success\n");
sleep(1);
break;
case 3:
chrt(0);
printf("proc3 set success\n");
sleep(1);
break;
}
for (loop = 1; loop < 30; loop++) {
if (id == 1 && loop == 5) {
chrt(5);
printf("Change proc1 deadline to 5s\n");
}
if (id == 3 && loop == 10) {
chrt(3);
printf("Change proc3 deadline to 3s\n");
}
sleep(1);
printf("prc%d heart beat %d\n", id, loop);
}
exit(0);
}
运行结果:
第一阶段P1、P2为实时进程,P3为用户进程,优先级P2>P1>P3
第二阶段P1、P2、P3都为实时进程,优先级P1>P2>P3
第三阶段P1进程结束,P2、P3为实时进程,优先级P3>P2,符合预期
总结
MINIX系统调用机制包含三层:应用层、服务层和内核层,层与层之间通过message传递消息。该实验本质上是将进程的deadline通过message逐层传递至内核层,并用deadline值进行进程调度决策。
在修改MINIX3内核过程中遇到了一些问题并分别尝试解决如下:
git clone在不同操作系统下不同的换行符(CRLF或LF)
我采用的编写方式是先将原来的MINIX3源码clone到windows10系统下,在本地修改后再将修改后的文件通过ssh传输到虚拟机。
但是git clone在windows系统和MINIX系统下文件的换行符有区别,windows下为CRLF,MINIX下为LF,这导致两边的文件不一致,编译时会报错。
在windows系统git中设置后使得windows系统下换行符也为LF。
设置命令:
git config --global core.autocrlf false
编译过程中遇到permission denied问题
通过chmod修改文件权限后解决
进程调度时,实时进程的优先级设置范围问题
实时进程的优先级设置不能过高,也不能过低。小于等于3时,可能会被视作系统进程和内核进程;大于等于7时,优先级可能会小于非实时进程。这些情况都会导致调度不能正确实现。经过了解和测试后选择实时进程优先级为5时可以正确实现。