MIT xv6 2020 系列实验:Lab4 traps

主要是一个内核调度alarm,定时中断并输出alarm。

任务一:backtrace

首先取出内核栈栈顶指针fp,对应到xv6的寄存器名是s0。

static inline uint64
r_fp()
{
  uint64 x;
  asm volatile("mv %0, s0" : "=r" (x) );
  return x;
}

backtrace:内核栈大小一页也就是4KB,其中fp往下依次存储上次的ra,与上次的栈指针pre。

进行循环遍历打印

void backtrace()
{
  uint64 fp = r_fp();
  uint64 up = PGROUNDUP(fp);
  uint64 down = PGROUNDDOWN(fp);
  while(fp < up && fp > down){
    uint64 ra = fp - 8;
    uint64 pre = fp - 16;
    printf("%p\n",*(uint64*)ra);
    fp = *(uint64*)pre;
  }
}

ra代表函数调用的位置。

然后即可在sys_sleep时实现backtrace。

任务二:sigalarm

uint64
sys_sigalarm(void){
  int ntick;
  uint64 f_ptr;
  if(argint(0, &ntick) < 0)
    return -1;
  if(argaddr(1,&f_ptr) < 0)
    return -1;
  acquire(&alarmlock);
  myproc()->interval = ntick;
  myproc()->handler = f_ptr;
  myproc()->xticks = 0;
  release(&alarmlock);
  return 0;
}

alarm传入两个参数:alarm周期与所调用的函数指针。这里直接赋值,对ntick为0的情况之后考虑。
这里一起考虑test0/1/2的部分:
系统调用处,在usertrap中进行修改:


  if(p->killed)
    exit(-1);
/*--------------------修改部分--------------------*/
  // give up the CPU if this is a timer interrupt.
  if(which_dev == 2){
    p->xticks += 1;
    if(p->xticks == p->interval){
      p->trapframe_bak = (struct trapframe*) kalloc();
      memmove(p->trapframe_bak,p->trapframe,sizeof(struct trapframe));
      p->trapframe->epc = p->handler;
    }
    yield();
  }
/*--------------------修改结束--------------------*/
  usertrapret();

如果p->interval为0,这里就不会有alarm调用,因为xticks直接永远不等于p->interval。
否则在触发定时器的过程中,每触发一次xticks递增1,在xticks与interval相等时就进行alarm函数的调用。
同时保存栈帧,用于对线程进行恢复。
最后还有还原的过程,在sigreturn中,要将线程恢复,则将p的trapframe_bak部分全部复制回p的trapframe中即可。


uint64
sys_sigreturn(void){
  struct proc *p = myproc();
  p->xticks = 0;
  memmove(p->trapframe,p->trapframe_bak,sizeof(struct trapframe));
  return 0;
}

如上,完成实验。

posted @   Thaudmin  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示