作业地址

整个作业根据给出的 Hint 完成就行

创建 alarmtest.c 文件,添加代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#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"); }

在 Makefile 中添加

1
2
UPROGS=\
  _alarmtest\

在 user.h 内添加

1
int alarm(int ticks, void (*handler)());

在 syscall.h 中添加

1
#define SYS_alarm  23

在 usys.S 中添加

1
SYSCALL(alarm)

在 proc.h 中 proc 结构体内添加间隔和指向处理函数的指针

1
2
3
4
5
struct proc {
  // ...
  int alarmticks;
  void (*alarmhandler)();
}

在 syscall.c 中添加相关系统调用 sys_alarm()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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;
}

在 syscall.c 中添加

1
2
3
4
5
6
extern int sys_alarm(void);

static int (*syscalls[])(void) = {
  // ...
  [SYS_alarm]   sys_alarm,
}

在 proc.h 中添加计数器

1
2
3
4
struct proc {
  // ...
  int cntticks;
}

在 trap.c 中 trap()T_IRQ0 + IRQ_TIMER 中添加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
switch(tf->trapno){
  case T_IRQ0 + IRQ_TIMER:
    // ...
    if (myproc() != 0 && (tf->cs & 3) == 3) {  // 只让 alarm 系统调用在用户态运行
      myproc()->cntticks++;
      if (myproc()->cntticks == myproc()->alarmticks &&
          tf->eip != (uint)myproc()->alarmhandler) {
        myproc()->cntticks = 0;
        // 当 alarmhandler 结束后,需要返回至引起 alarm 系统调用的代码处
        // 在中断发生后处于 kernel mode 所以不会保存寄存器值,要手动保存
        // 将 eip 压栈
        tf->esp -= 4;
        *((uint *)(tf->esp)) = tf->eip;
        // 将 alarmhandler 复制给 eip
        tf->eip = (uint)myproc()->alarmhandler;
      }

    }
    lapiceoi();
    break;
}