时钟中断

RISC-V的CPU在一定的时间段就会触发一次时钟中断,RISC-V希望时钟中断能在M态处理而不是在S态处理.我们选择在一个特殊的方法来处理时钟中断.

start.c中,我们设置了把所有中断都放在S态进行处理.但是我们在timerinit函数中创建了一个专属于时钟中断的处理模式,在这个函数中,我们主要是获得了时钟中断的锁.

当时钟中断产生的时候,我们一般认为这个中断是一个设备中断:在devintr函数中我们看到了时钟中断的处理逻辑:

	else if (0x8000000000000005L == scause) {
		timer_tick();
		return 2;
	}

每一次时钟中断都会调用timer_tick函数:

  • 通知因为sleep导致睡眠的进程.

  • 设置下一次时钟中断的时间.

void timer_tick() {
    acquire(&tickslock);
    ticks++;
    wakeup(&ticks);
    release(&tickslock);
    set_next_timeout();
}

set_next_timeout函数中,我们通过sbi接口设置了下一次时钟中断的时间:

void
set_next_timeout() {
    // There is a very strange bug,
    // if comment the `printf` line below
    // the timer will not work.

    // this bug seems to disappear automatically
    // printf("");
    sbi_set_timer(r_time() + INTERVAL);
}

为了适配进程的时间计数,我们在每一次时钟中断的时候添加了proc_tick()函数:

void proc_tick(void) {
	// runnable 
    struct proc* p;
    struct proc* np;
	for(p = proc; p < &proc[NPROC]; p++) {
      acquire(&p->lock);
      p->proc_tms.utime += 1;
      p->proc_tms.stime += 1;
      np = p->parent;
      while(np){
        np->proc_tms.cstime += p->proc_tms.stime + p->proc_tms.cstime;
				np->proc_tms.cutime += p->proc_tms.utime + p->proc_tms.cutime;
        np = np->parent;
      }
      release(&p->lock);
  }
}

这个函数我们主要是处理tms结构体里面的数据:

struct tms {
	uint64 utime;		// user time 
	uint64 stime;		// system time 
	uint64 cutime;		// user time of children 
	uint64 cstime;		// system time of children 
};

我们在每一个时钟周期对tms进行一次处理即可.

Last updated