add alarmtest.c to the repository

they don't have to modify alarmtest.c, so we can use the
original version to test, to make it harder to cheat.
feat/start
Robert Morris 2019-08-05 02:04:44 -04:00
parent deec67f05d
commit d96a8c5661
2 changed files with 118 additions and 84 deletions

View File

@ -117,72 +117,13 @@ time in xv6, determined by how often a hardware timer generates
interrupts.
<p>
You should put the following test program in <tt>user/alarmtest.c</tt>:
You'll find a file <tt>user/alarmtest.c</tt> in your xv6
repository. Add it to the Makefile. It won't compile correctly
until you've added <tt>sigalarm</tt> and <tt>sigreturn</tt>
system calls (see below).
<pre>
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/riscv.h"
#include "user/user.h"
void test0();
void test1();
void periodic();
int
main(int argc, char *argv[])
{
test0();
test1();
exit();
}
void test0()
{
int i;
printf(1, "test0 start\n");
sigalarm(2, periodic);
for(i = 0; i < 1000*500000; i++){
if((i % 250000) == 0)
write(2, ".", 1);
}
sigalarm(0, 0);
printf(1, "test0 done\n");
}
void
periodic()
{
printf(1, "alarm!\n");
}
void __attribute__ ((noinline)) foo(int i, int *j) {
if((i % 2500000) == 0) {
write(2, ".", 1);
}
*j += 1;
}
void test1() {
int i;
int j;
printf(1, "test1 start\n");
j = 0;
sigalarm(2, periodic);
for(i = 0; i < 1000*500000; i++){
foo(i, &j);
}
if(i != j) {
printf(2, "i %d should = j %d\n", i, j);
exit();
}
printf(1, "test1 done\n");
}
</pre>
The program calls <tt>sigalarm(2, periodic1)</tt> in <tt>test0</tt> to
<p>
<tt>alarmtest</tt> calls <tt>sigalarm(2, periodic)</tt> in <tt>test0</tt> to
ask the kernel to force a call to <tt>periodic()</tt> every 2 ticks,
and then spins for a while.
You can see the assembly
@ -194,24 +135,23 @@ When you've finished the lab,
<pre>
$ alarmtest
test0 start
...................................................alarm!
.............................................................alarm!
(repeated many times)
test0 done
......................................alarm!
test0 passed
test1 start
..alarm!
..alarm!
..alarm!
(repeated many times)
test1 done
.alarm!
..alarm!
..alarm!
..alarm!
..alarm!
..alarm!
..alarm!
test1 passed
$
</pre>
<p>
At first, however, you'll see that alarmtest only prints periods,
and doesn't print "alarm!".
<p>The main challenge will be to arrange that the handler is invoked
when the process's alarm interval expires. You'll need to modify
usertrap() in kernel/trap.c so that when a
@ -223,6 +163,9 @@ and doesn't print "alarm!".
<p>Your solution will be only a few lines of code, but it may be tricky to
get it right.
We'll test your code with the version of alarmtest.c in the original
repository; if you modify alarmtest.c, make sure your kernel changes
cause the original alarmtest to pass the tests.
<h3>test0: invoke handler</h3>
@ -236,15 +179,18 @@ program crashes after printing "alarm!". Here are some hints:
<li>You'll need to modify the Makefile to cause <tt>alarmtest.c</tt>
to be compiled as an xv6 user program.
<li>The right declaration to put in <tt>user/user.h</tt> is:
<li>The right declarations to put in <tt>user/user.h</tt> are:
<pre>
int sigalarm(int ticks, void (*handler)());
int sigreturn(void);
</pre>
<li>Update user/sys.pl (which generates user/usys.S),
kernel/syscall.h, and kernel/syscall.c
to allow <tt>alarmtest</tt> to invoke the sigalarm system
call.
to allow <tt>alarmtest</tt> to invoke the sigalarm and
sigreturn system calls.
<li>For now, your <tt>sys_sigreturn</tt> should just return zero.
<li>Your <tt>sys_sigalarm()</tt> should store the alarm interval and
the pointer to the handler function in new fields in the <tt>proc</tt>
@ -300,15 +246,15 @@ can continue undisturbed after the alarm.
<p>Your solution is likely to require you to save and restore
registers---what registers do you need to save and restore to resume
the interrupted code correctly? (Hint: it will be many).
Several approaches are possible; one convenient plan is to add another
system call <tt>sigreturn</tt> that the user-space alarm handler calls when it is
done, and which restores registers and returns to the original
Several approaches are possible; for this lab you should make
the <tt>sigreturn</tt> system call
restore registers and return to the original
interrupted user instruction.
The user-space alarm handler
calls sigreturn when it is done.
Some hints:
<ul>
<li>Add a new <tt>sigreturn</tt> system call.
<li>Have <tt>usertrap</tt> save enough state in
<tt>struct proc</tt> when the timer goes off
that <tt>sigreturn</tt> can correctly return to the

88
user/alarmtest.c Normal file
View File

@ -0,0 +1,88 @@
//
// test program for the alarm lab.
// you can modify this file for testing,
// but please make sure your kernel
// modifications pass the original
// versions of these tests.
//
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/riscv.h"
#include "user/user.h"
void test0();
void test1();
void periodic();
int
main(int argc, char *argv[])
{
test0();
test1();
exit();
}
volatile static int count;
void
periodic()
{
count = count + 1;
printf(1, "alarm!\n");
sigreturn();
}
// tests whether the kernel calls
// the alarm handler even a single time.
void
test0()
{
int i;
printf(1, "test0 start\n");
count = 0;
sigalarm(2, periodic);
for(i = 0; i < 1000*500000; i++){
if((i % 250000) == 0)
write(2, ".", 1);
if(count > 0)
break;
}
sigalarm(0, 0);
if(count > 0){
printf(1, "test0 passed\n");
} else {
printf(1, "test0 failed\n");
}
}
void __attribute__ ((noinline)) foo(int i, int *j) {
if((i % 2500000) == 0) {
write(2, ".", 1);
}
*j += 1;
}
void
test1()
{
int i;
int j;
printf(1, "test1 start\n");
count = 0;
j = 0;
sigalarm(2, periodic);
for(i = 0; i < 500000000; i++){
if(count >= 10)
break;
foo(i, &j);
}
if(i != j || count < 10){
// i should equal j
printf(1, "test1 failed\n");
} else {
printf(1, "test1 passed\n");
}
}