Homework5: xv6 CPU alarm

在本练习中,将在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 like
    if(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有关于寄存器的练习必须要重新来过了...

猜你喜欢

转载自blog.csdn.net/qq_43012789/article/details/107922107