Alarm(Hard)
添加一个新的sigalarm(interval, handler)系统调用
test0: invoke handler(调用处理程序)
添加系统调用流程(类似Lab2)
修改Makefile以使alarmtest.c被编译为xv6用户程序
diff --git a/Makefile b/Makefile
index 1fa367e..f5da769 100644
--- a/Makefile
+++ b/Makefile
@@ -175,7 +175,7 @@ UPROGS=\
$U/_grind\
$U/_wc\
$U/_zombie\
$U/_alarmtest\
放入user/user.h的正确声明
diff --git a/user/user.h b/user/user.h
index b71ecda..57404e0 100644
--- a/user/user.h
+++ b/user/user.h
@@ -23,6 +23,8 @@ int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);
int sigalarm(int ticks, void (*handler)());
int sigreturn(void);
// ulib.c
int stat(const char*, struct stat*);
更新user/usys.pl
此文件生成user/usys.S
diff --git a/user/usys.pl b/user/usys.pl
index 01e426e..fa548b0 100755
--- a/user/usys.pl
+++ b/user/usys.pl
@@ -36,3 +36,5 @@ entry("getpid");
entry("sbrk");
entry("sleep");
entry("uptime");
entry("sigalarm");
entry("sigreturn");
更新kernel/syscall.h和kernel/syscall.c
以此允许alarmtest调用sigalarm和sigreturn系统调用
diff --git a/kernel/syscall.h b/kernel/syscall.h
index bc5f356..7b88b81 100644
--- a/kernel/syscall.h
+++ b/kernel/syscall.h
@@ -20,3 +20,5 @@
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
#define SYS_sigalarm 22
#define SYS_sigreturn 23
diff --git a/kernel/syscall.c b/kernel/syscall.c
index c1b3670..8c0a928 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -104,6 +104,8 @@ extern uint64 sys_unlink(void);
extern uint64 sys_wait(void);
extern uint64 sys_write(void);
extern uint64 sys_uptime(void);
extern uint64 sys_sigalarm(void);
extern uint64 sys_sigreturn(void);
static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork,
@@ -127,6 +129,8 @@ static uint64 (*syscalls[])(void) = {
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
[SYS_sigalarm] sys_sigalarm,
[SYS_sigreturn] sys_sigreturn,
};
void
sys_sigreturn和sys_sigalarm系统调用
sys_sigreturn系统调用返回应该是零
sys_sigalarm()应该将报警间隔和指向处理程序函数的指针存储在struct proc的新字段中
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index fd19d2a..f3c86d8 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -96,3 +96,26 @@ sys_uptime(void)
release(&tickslock);
return xticks;
}
uint64
sys_sigalarm(void)
{
int interval;
uint64 handler;
argint(0, &interval);
argaddr(1, &handler);
struct proc *p = myproc();
p->interval = interval;
p->handler = handler;
p->ticks = 0;
return 0;
}
uint64
sys_sigreturn(void)
{
return 0;
}
\ No newline at end of file
proc字段
在struct proc新增一个新字段。用于跟踪自上一次调用(或直到下一次调用)到进程的报警处理程序间经历了多少滴答
diff --git a/kernel/proc.h b/kernel/proc.h
index 9c16ea7..3e5cd13 100644
--- a/kernel/proc.h
+++ b/kernel/proc.h
@@ -103,4 +103,8 @@ struct proc {
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
int interval;
uint64 handler;
int ticks;
};
在proc.c的allocproc()中初始化proc字段
diff --git a/kernel/proc.c b/kernel/proc.c
index dab1e1d..cae7085 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -126,6 +126,9 @@ found:
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
p->interval = 0;
p->handler = 0;
p->ticks = 0;
return p;
}
中断在kernel/trap.c中的usertrap()中处理
每一个滴答声,硬件时钟就会强制一个中断
diff --git a/kernel/trap.c b/kernel/trap.c
index a63249e..8230374 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -78,7 +78,16 @@ usertrap(void)
// give up the CPU if this is a timer interrupt.
if(which_dev == 2)
{
if(p->interval != 0){
p->ticks++;
if(p->ticks > p->interval){
p->ticks = 0;
p->trapframe->epc = p->handler;
}
}
yield();
}
usertrapret();
}
什么决定了用户空间代码恢复执行的指令地址?
在proc.h第48行
/* 24 */ uint64 epc; // saved user program counter
用户空间的pc
结果
bash
$ alarmtest
test0 start
................................................alarm!
test0 passed
test1/test2(): resume interrupted code(恢复被中断的代码)
修改 proc 结构体
增加 trapframe 的副本字段
diff --git a/kernel/proc.h b/kernel/proc.h
index 3e5cd13..c8aa74d 100644
--- a/kernel/proc.h
+++ b/kernel/proc.h
@@ -107,4 +107,5 @@ struct proc {
int interval;
uint64 handler;
int ticks;
struct trapframe* trapframecopy;
};
与test0相同将其在proc中进行初始化
diff --git a/kernel/proc.c b/kernel/proc.c
index cae7085..704c016 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -129,6 +129,7 @@ found:
p->interval = 0;
p->handler = 0;
p->ticks = 0;
p->trapframecopy = 0;
return p;
}
保留现场
在 kernel/trap.c 的 usertrap() 中覆盖 p->trapframe->epc 前做 trapframe 的副本
diff --git a/kernel/trap.c b/kernel/trap.c
index 8230374..6d0ba1c 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -81,8 +81,9 @@ usertrap(void)
{
if(p->interval != 0){
p->ticks++;
if(p->ticks > p->interval){
p->ticks = 0;
if(p->ticks == p->interval){
p->trapframecopy = p->trapframe + 512;
memmove(p->trapframecopy,p->trapframe,sizeof(struct trapframe));
p->trapframe->epc = p->handler;
}
}
使用memmove函数进行复制整个trapframe
512是使用trapframe空间后面的内存, trapframe实际内存大小为288B, 可以取其他值
恢复现场
在 sys_sigreturn() 中将副本恢复到原 trapframe
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index f3c86d8..242a0d1 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -117,5 +117,13 @@ sys_sigalarm(void)
uint64
sys_sigreturn(void)
{
return 0;
struct proc *p = myproc();
if(p->trapframecopy != p->trapframe + 512) {
return -1;
}
memmove(p->trapframe, p->trapframecopy, sizeof(struct trapframe));
p->ticks = 0;
p->trapframecopy = 0;
return p->trapframe->a0;
}
\ No newline at end of file
防止对handler程序的重复调用
- 将p->ticks=0从原本的 usertrap() 移至 sys_sigreturn() 中
若在usetrap()中进行重置,ticks后续会自增又会满足handler调用条件
而sys_sigreturn()的结束对应handler()的结束,所以移动到此处
- 注意当ticks达到 interval 时调用handler()
结果
测试test0、test1和test2
bash
$ alarmtest
test0 start
.............................alarm!
test0 passed
test1 start
....alarm!
...alarm!
....alarm!
....alarm!
....alarm!
.....alarm!
....alarm!
.....alarm!
....alarm!
.....alarm!
test1 passed
test2 start
......................................................alarm!
test2 passed
usertests
确保没有破坏内核的任何其他部分
bash
ALL TESTS PASSED
$