diff --git a/kernel/printf.c b/kernel/printf.c index f0a7055..777b0b3 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -177,6 +177,7 @@ printfinit(void) pr.locking = 1; } +// 打印当前调用栈的返回地址,实现简单的函数回溯,用于调试。 void backtrace(void) { @@ -185,11 +186,12 @@ backtrace(void) uint64 ra,fp = r_fp();//frame pointer -> address uint64 pre_fp = *((uint64*)(fp - 16)); + // 只要当前fp和上一个fp在同一页内,就继续回溯 while(PGROUNDDOWN(fp)==PGROUNDDOWN(pre_fp)){ - ra = *(uint64 *)(fp - 8); - printf("%p\n", (void*)ra); - fp = pre_fp; - pre_fp = *((uint64*)(fp - 16)); + ra = *(uint64 *)(fp - 8); // 取出返回地址 + printf("%p\n", (void*)ra); // 打印返回地址 + fp = pre_fp; // 更新fp为上一个fp + pre_fp = *((uint64*)(fp - 16)); // 获取新的上一个fp } ra = *(uint64 *)(fp - 8); diff --git a/kernel/proc.c b/kernel/proc.c index 1d41012..beced5f 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -132,6 +132,7 @@ found: return 0; } + // 为进程分配 pre_trapframe 空间,分配失败则释放进程资源并返回 0 if((p->pre_trapframe = (struct trapframe *)kalloc()) == 0){ freeproc(p); release(&p->lock); @@ -166,6 +167,7 @@ freeproc(struct proc *p) p->trapframe = 0; if(p->pagetable) proc_freepagetable(p->pagetable, p->sz); + // 如果进程的 pre_trapframe 存在,则释放其占用的内存,并将指针置为 0,防止悬空指针。 if(p->pre_trapframe) kfree((void*)p->pre_trapframe); p->pre_trapframe = 0; diff --git a/kernel/proc.h b/kernel/proc.h index f7fc14c..b3adfb7 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -104,8 +104,8 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) - int alarm_cnt; // Alarm count - int inter_cnt; // interrupts count - uint64 handler; // alarm func address + int alarm_cnt; // Alarm count 触发alarm的时钟中断数量 + int inter_cnt; // interrupts count 需要统计的时钟中断的数量 + uint64 handler; // alarm func address 记录处理alarm的函数的地址 struct trapframe *pre_trapframe; }; diff --git a/kernel/riscv.h b/kernel/riscv.h index e6b00e2..e81715e 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -338,6 +338,7 @@ r_ra() return x; } +// 读取当前帧指针(s0)寄存器的值 static inline uint64 r_fp() { diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 0d9e9a3..cd59988 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -94,6 +94,22 @@ sys_uptime(void) return xticks; } +// sys_sigalarm函数用于设置进程的定时信号处理机制。 +// 参数: +// alarm_cnt:定时器计数值,表示每经过alarm_cnt个时钟中断后触发一次信号处理。 +// addr:信号处理函数的用户空间地址。 +// 实现: +// 1. 通过argint和argaddr获取用户传入的参数。 +// 2. 将进程的inter_cnt(中断计数器)清零。 +// 3. 保存信号处理函数地址和定时器计数值到进程结构体。 +// 4. 返回0,表示设置成功。 + +// sys_sigreturn函数用于在信号处理函数执行完毕后恢复进程的上下文。 +// 实现: +// 1. 获取当前进程指针。 +// 2. 将trapframe恢复为信号处理前保存的pre_trapframe,恢复进程上下文。 +// 3. 将inter_cnt(中断计数器)清零,重新计数。 +// 4. 返回信号处理前a0寄存器的值,作为系统调用的返回值。 uint64 sys_sigalarm(void) { diff --git a/kernel/trap.c b/kernel/trap.c index 64d87aa..617615d 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -76,13 +76,18 @@ usertrap(void) if(killed(p)) exit(-1); - // give up the CPU if this is a timer interrupt. + // 如果这是一个定时器中断,则让出CPU。 if(which_dev == 2){ + // 当前进程的中断计数器加一。 p->inter_cnt++; + // 如果中断计数器达到设定的报警计数,并且报警计数大于0。 if (p->inter_cnt == p->alarm_cnt && 0 < p->alarm_cnt) { + // 备份当前trapframe到pre_trapframe,用于后续恢复。 *p->pre_trapframe = *p->trapframe; + // 将epc设置为用户定义的handler函数地址,返回用户态时会跳转到handler执行。 p->trapframe->epc = p->handler; } else { + // 否则让出CPU,进行进程调度。 yield(); } }