当前位置: 代码迷 >> 综合 >> Homework5: xv6 CPU alarm
  详细解决方案

Homework5: xv6 CPU alarm

热度:14   发布时间:2024-02-09 12:57:29.0

在本练习中,将在xf6中添加一项功能,当进程使用CPU时间时,它会定期向进程发出警报。这对于希望限制占用多少CPU时间的受计算限制的进程,或者希望进行计算但又希望采取一些周期性操作的进程可能很有用。更一般地说,您将实现用户级中断/故障处理程序的原始形式;例如,您可以使用类似的东西来处理应用程序中的页面错误。

需要添加一个新的alarm(interval, handler)系统调用。如果一个应用程序调用了alarm(n,fn), 那么在程序消耗每个n“ticks”的CPU时间之后,内核将调用应用程序函数fn。 当fn返回时,应用程序将从中断处继续。 tick是xv6中相当随意的时间单位,由硬件定时器产生中断的频率决定。

把下述样例程序放到文件alarmtest.c中。该程序调用alarm(10,periodic),要求内核每10秒钟强制调用periodic(),然后旋转一会儿。

#include "types.h"
#include "stat.h"
#include "user.h"void periodic();int
main(int argc, char *argv[])
{int i;printf(1, "alarmtest starting\n");alarm(10, periodic);for(i = 0; i < 25*500000; i++){if((i % 250000) == 0)write(2, ".", 1);}exit();
}void
periodic()
{printf(1, "alarm!\n");
}

实验内容

在内核中实现了alarm()系统调用后,alarmtest应该会产生如下输出:

$ alarmtest
alarmtest starting
.....alarm!
....alarm!
.....alarm!
......alarm!
.....alarm!
....alarm!
....alarm!
......alarm!
.....alarm!
...alarm!
...$ 

实验过程

首先参考HW3, 添加alarm的系统调用。

syscall.c:107:extern int sys_alarm(void);
syscall.c:132:[SYS_alarm]   sys_alarm,
syscall.c:158:[SYS_alarm]   "alarm"
syscall.h:24:#define SYS_alarm  23
sysproc.c:103:sys_alarm(void){
user.h:27:int alarm(int ticks, void (*handler)());
usys.S:33:SYSCALL(alarm)
//sysproc.c
int
sys_alarm(void){int ticks;void (*handler)();if(argint(0, &ticks) < 0)return -1;if(argptr(1, (char**)&handler, 1) < 0)return -1;myproc()->alarmticks = ticks;myproc()->alarmhandler = handler;return 0;}
Hint: Your sys_alarm() should store the alarm interval and the pointer to the handler function in new fields in the proc structure; see proc.h. int alarmticks;   //总时间个数int curticks;    //当前时钟个数void (*alarmhandler)();
 /*
Hint: You only want to manipulate a process's alarm ticks if there's a process running and if the timer interrupt came from user space; you want something likeif(myproc() != 0 && (tf->cs & 3) == 3) ...
Hint: In your IRQ_TIMER code, when a process's alarm interval expires, you'll want to cause it to execute its handler. How can you do that?
Hint: You need to arrange things so that, when the handler returns, the process resumes executing where it left off. How can you do that?
Hint: You can see the assembly code for the alarmtest program in alarmtest.asm. 
*/case T_IRQ0 + IRQ_TIMER:if(cpuid() == 0){acquire(&tickslock);ticks++;wakeup(&ticks);release(&tickslock);}if(myproc()!=0 && (tf->cs&3)==3){myproc()->curticks++;//cprintf("curticks= %d, alarmticks= %d\n",myproc()->curticks, myproc()->alarmticks);if(myproc()->curticks==myproc()->alarmticks){myproc()->curticks = 0;//寄存器tf->esp-=4;*(uint *)(tf->esp) = tf->eip;tf->eip= (uint)myproc()->alarmhandler;}}lapiceoi();break;

make qemu,然后输入命令alarmtest,发现结果是这样

不对惹...我把curticks和alarmticks输出,发现输出了一次alarm之后,就停止了,于是想到了官方给出的提示:把迭代次数翻10倍。

 for(i = 0; i < 250*500000; i++){
//把25改成250

再次尝试,成功!

总结

总体来说,只要掌握了HW3,这里的代码就不难。寄存器部分的代码是我永远的痛!一碰到就不会写,甚至根本都不会想到去编辑寄存器...Lab1有关于寄存器的练习必须要重新来过了...