作业地址:xv6 CPU alarm
此次作业就是添加一个系统调用alarm(),可以周期性的进行某个函数的调用。
Step 1
在user.h中添加这个系统函数的声明:
int alarm(int ticks,void(*handler)());
Step 2
在syscall.h中添加该调用的号码:
#define SYS_alarm 22
Step 3
在usys.S里面添加进入内核的入口:
SYSCALL(alarm)
Step 4
在syscall.c添加对初始参数进行设置的系统调用:
extern int sys_alarm(void);
[SYS_alarm] sys_alarm,
Step 5
在sysproc.c中添加sys_alarm函数的具体实现(作业里面已经给我们提供了):
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;
}
可以看到pro这个结构体里面多了两个成员:alarmticks
和alarmhandler
,所以我们要将结构体里面进行相应的扩展。
Step 6
在proc.h的proc结构体里面添加两个成员:
int alarmticks;
void (*alarmhandler)();
并且在proc.c的static struct proc* allocproc(void)
对其进行初始化:
p->alarmticks = 0;
p->alarmhandler = 0;
Step 7
在trap.c中对trap()函数进行相应的扩展,当ticks满足我们设置的数量的时候,就调用alarmhandler函数:
if (myproc() != 0 && (tf->cs & 3) == 3)
{
sum_ticks ++;
if (sum_ticks == myproc()->alarmticks)
{
sum_ticks = 0;
tf->esp -= 4;
*((uint*)tf->esp) = tf->eip;
tf->eip = (uint)(myproc()->alarmhandler);
}
}
这里的逻辑为:
退出内核后,马上执行alarmhandler函数,在alarmhandler执行完毕之后,再执行用户程序中断处的语句。
值得注意的是,如果直接在trap()里面调用
myproc()->alarmhandler(),程序不会崩溃,但是不会打印"alarm!“字样。究其原因,直接调用,此时的栈仍然为内核栈,函数periodic()里面依然有系统调用。所以此时是在内核态进行系统调用,压入的寄存器值不是正常的用户寄存器,而是在此内核态下的寄存器值,就不会打印"alarm!”。
END.