6.S081 lab4 traps
#Backtrace#
-
在
kernel/riscv.h
中添加hints
所给的r_fp
函数,这个函数的作用是取出s0
寄存器的值,该寄存器保存了当前的帧指针。栈帧的布局图如下:可以看出返回地址和前一个栈帧的帧指针的保存位置是固定的,分别为
fp-8
和fp-16
。 -
弄懂这个图就很容易写出代码了,首先调用
r_fp
读取当前的帧指针,通过PGROUNDUP
对其页面上取整,这里对页面上取整的原因是:可能一个物理页中有多个栈帧嵌套,我们需要打印出所有的返回地址。代码如下:复制
void backtrace(void) { printf("backtrace:\n"); // 读取当前帧指针 uint64 fp = r_fp(); uint64 base = PGROUNDUP(fp); while (fp < base){ uint64 ret_adr = *(uint64*)(fp - 8); printf("%p\n", ret_adr); // 前一个帧指针 fp = *(uint64*)(fp - 16); } }
#Alarm#
做这个实验之前,一定要弄清楚
xv6
处理trap
的过程,建议好好看一下xv6 book
的第四章
-
加入系统调用原型等操作不再赘述。在
struct proc
中加入以下字段。alarm_interval
:报警间隔alarm_handler
:指向处理函数的指针ticks_count
:距离上一次定时器中断所经历的ticks
alarm_trapframe
:发生定时器中断时,进程的trapframe
,用来恢复进程的执行flag
:标记上一次的报警处理程序是否已经执行完,0
表示已处理完报警。
-
更改
usertrap
以处理计时器中断。当发生计时器中断时,whick_dev
的值为2
。注意到指向报警处理函数指针可能为空,只有当指针不为空时,才进行相应的处理。代码如下:复制
void usertrap(void) { ... // give up the CPU if this is a timer interrupt. if(which_dev == 2){ if (p->alarm_interval){ p->ticks_count++; if (p->ticks_count == p->alarm_interval && p->flag == 0){ p->alarm_trapframe = *p->trapframe; p->trapframe->epc = (uint64)p->alarm_handler; p->flag = 1; p->ticks_count = 0; } } yield(); } usertrapret(); }
每发生一次定时器中断,
ticks_count
就加1
,如果此时已经达到了报警间隔并且没有正在处理的报警,则设置相应的参数以转至报警处理函数。注意到上述代码的第11
行,进程的trapframe->epc
保存了进程下一条指令的地址,把其设置为报警处理函数的地址以便进程跳转到报警处理函数。再看到上述代码的第10
行,由于进程执行完报警处理函数之后,应该恢复到原来的执行流,故此处的alarm_trapframe
保存了进程被中断时相关的寄存器。设置flag
以标记本次报警处理还未完成。 -
实现
sys_sigalarm
函数,该函数有两个参数(报警间隔和报警处理函数的指针),分别给进程的两个成员赋值即可。代码如下:复制
uint64 sys_sigalarm(void) { struct proc *p = myproc(); if (argint(0, &p->alarm_interval) < 0 || argaddr(1, (uint64*)&p->alarm_handler) < 0) return -1; /* printf("%d %d\n", p->alarm_interval, p->alarm_handler); */ return 0; }
-
实现
sys_sigreturn
函数,由于报警处理函数结束后,需要恢复进程被定时器中断时的执行流,把p->trapframe
恢复到p->alarm_trapframe
。该函数被调用时,标志着报警处理函数已经结束,所以应该把flag
设置为0
。代码如下:复制
uint64 sys_sigreturn(void) { struct proc *p = myproc(); p->flag = 0; *p->trapframe = p->alarm_trapframe; return 0; }
-
在分配进程的
allocproc
函数中添加新字段的初始化:复制
static struct proc* allocproc(void) { ... found: ... p->flag = 0; p->alarm_interval = 0; p->ticks_count = 0; ... return p; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通