alarm stuff

This commit is contained in:
Robert Morris 2019-08-03 07:12:00 -04:00
parent fdea265489
commit deec67f05d

View file

@ -7,10 +7,10 @@
<h1>Lab: Alarm and uthread</h1> <h1>Lab: Alarm and uthread</h1>
This lab makes you familiar with the implementation of system calls This lab will familiarize you with the implementation of system calls
and switching between threads of execution. In particular, you will and switching between threads of execution. In particular, you will
implement new system calls (<tt>sigalarm</tt> and <tt>sigreturn</tt>) implement new system calls (<tt>sigalarm</tt> and <tt>sigreturn</tt>)
and switching between threads of a user-level thread package. and switching between threads in a user-level thread package.
<h2>Warmup: RISC-V assembly</h2> <h2>Warmup: RISC-V assembly</h2>
@ -119,7 +119,6 @@ interrupts.
<p> <p>
You should put the following test program in <tt>user/alarmtest.c</tt>: You should put the following test program in <tt>user/alarmtest.c</tt>:
<b>XXX Insert the final program here; maybe just give the code in the repo</b>
<pre> <pre>
#include "kernel/param.h" #include "kernel/param.h"
#include "kernel/types.h" #include "kernel/types.h"
@ -143,12 +142,12 @@ void test0()
{ {
int i; int i;
printf(1, "test0 start\n"); printf(1, "test0 start\n");
alarm(2, periodic); sigalarm(2, periodic);
for(i = 0; i < 1000*500000; i++){ for(i = 0; i < 1000*500000; i++){
if((i % 250000) == 0) if((i % 250000) == 0)
write(2, ".", 1); write(2, ".", 1);
} }
alarm(0, 0); sigalarm(0, 0);
printf(1, "test0 done\n"); printf(1, "test0 done\n");
} }
@ -171,7 +170,7 @@ void test1() {
printf(1, "test1 start\n"); printf(1, "test1 start\n");
j = 0; j = 0;
alarm(2, periodic); sigalarm(2, periodic);
for(i = 0; i < 1000*500000; i++){ for(i = 0; i < 1000*500000; i++){
foo(i, &j); foo(i, &j);
} }
@ -185,54 +184,52 @@ void test1() {
The program calls <tt>sigalarm(2, periodic1)</tt> in <tt>test0</tt> to The program calls <tt>sigalarm(2, periodic1)</tt> in <tt>test0</tt> to
ask the kernel to force a call to <tt>periodic()</tt> every 2 ticks, ask the kernel to force a call to <tt>periodic()</tt> every 2 ticks,
and then spins for a while. After you have implemented and then spins for a while.
the <tt>sigalarm()</tt> system call in the kernel, You can see the assembly
<tt>alarmtest</tt> should produce output like this for <tt>test0</tt>: code for alarmtest in user/alarmtest.asm, which may be handy
for debugging.
When you've finished the lab,
<tt>alarmtest</tt> should produce output like this:
<b>Update output for final usertests.c</b>
<pre> <pre>
$ alarmtest $ alarmtest
alarmtest starting test0 start
.....alarm! ...................................................alarm!
....alarm! .............................................................alarm!
.....alarm! (repeated many times)
......alarm! test0 done
.....alarm! test1 start
....alarm! ..alarm!
....alarm! ..alarm!
......alarm! ..alarm!
.....alarm! (repeated many times)
...alarm! test1 done
...$ $
</pre> </pre>
<p>
<p> <p>
(If you only see one "alarm!", try increasing the number of iterations in At first, however, you'll see that alarmtest only prints periods,
<tt>alarmtest.c</tt> by 10x.) and doesn't print "alarm!".
<p>The main challenge will be to arrange that the handler is invoked <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 when the process's alarm interval expires. You'll need to modify
usertrap() in kernel/trap.c so that when a usertrap() in kernel/trap.c so that when a
process's alarm interval expires, the process executes process's alarm interval expires, the process executes
the handler. How can you do that? You will need to understand in the handler. How can you do that? You will need to understand
detail how system calls work (i.e., the code in kernel/trampoline.S how system calls work (i.e., the code in kernel/trampoline.S
and kernel/trap.c). Which register contains the address where and kernel/trap.c). Which register contains the address to which
system calls return to? system calls return?
<p>Your solution will be few lines of code, but it will be tricky to <p>Your solution will be only a few lines of code, but it may be tricky to
write the right lines of code. The most common failure scenario is that the get it right.
user program crashes or doesn't terminate. You can see the assembly
code for the alarmtest program in alarmtest.asm, which will be handy
for debugging.
<h3>Test0: invoke handler</h3> <h3>test0: invoke handler</h3>
<p>To get started, the best strategy is to first pass test0, which <p>Get started by modifying the kernel to jump to the alarm handler in
will force you to handle the main challenge above. Here are some user space, which will cause test0 to print "alarm!". Don't worry yet
hints how to pass test0: what happens after the "alarm!" output; it's OK for now if your
program crashes after printing "alarm!". Here are some hints:
<p><b>XXX alarm() needs to be defined somewhere.</b><br>
<ul> <ul>
@ -268,7 +265,7 @@ in <tt>usertrap()</tt>; you should add some code here.
if(which_dev == 2) ... if(which_dev == 2) ...
</pre> </pre>
<li>Only invoke the process's alarm function, if the process has a <li>Only invoke the alarm function if the process has a
timer outstanding. Note that the address of the user's alarm timer outstanding. Note that the address of the user's alarm
function might be 0 (e.g., in alarmtest.asm, <tt>periodic</tt> is at function might be 0 (e.g., in alarmtest.asm, <tt>periodic</tt> is at
address 0). address 0).
@ -279,41 +276,32 @@ use only one CPU, which you can do by running
make CPUS=1 qemu make CPUS=1 qemu
</pre> </pre>
<li><b>XXX we need to somehow convey what it is they don't <li>You've succeeded if alarmtest prints "alarm!".
need to do here, i.e. what part is to be left to
the next section.</b>
<li><b>XXX it's not clear how they can tell whether they
are passing test0(), and should proceed to the next section.
do they need to make sure at this point that they see multiple
alarm! printouts? or is it OK if they see one alarm! and
then a crash? may need to fix the sample ...alarm! output shown above</b>
</ul> </ul>
<h3>test1(): resume interrupted code</h3> <h3>test1(): resume interrupted code</h3>
<p><b>XXX it is surprising that test0() appears to work Chances are that alarmtest crashes at some point after it prints
perfectly, even though something is seriously wrong "alarm!". Depending on how your solution works, that point may be in
with the way periodic() returns. we should recognize test0, or it may be in test1. Crashes are likely caused
that something odd is happening, maybe ask them to think by the alarm handler (<tt>periodic</tt> in alarmtest.c) returning
about it, and hint or say why they are not done even though to the wrong point in the user program.
test0() works.</b>
<p>Test0 doesn't test whether the handler returns correctly to <p>
the user instruction that was interrupted by the timer. Your job now is to ensure that, when the alarm handler is done,
The previous section didn't require you to get this right. control returns to
If you didn't, test0 will probably succeed anyway, but the instruction at which the user program was originally
test1 will likely fail (the program crashes or the program interrupted by the timer interrupt. You must also ensure that
goes into an infinite loop). the register contents are restored to values they held
Another challenge is that the register contents need to be at the time of the interrupt, so that the user program
correct when control returns to the interrupted user instruction. can continue undisturbed after the alarm.
<p>Your solution is likely to require you to save and restore <p>Your solution is likely to require you to save and restore
registers---what registers do you need to save and restore to resume registers---what registers do you need to save and restore to resume
the interrupted code correctly? (Hint: it will be many). There are the interrupted code correctly? (Hint: it will be many).
several ways to restore the registers; one convenient plan is to add another Several approaches are possible; one convenient plan is to add another
system call <tt>sigreturn</tt> that the handler calls when it is 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 done, and which restores registers and returns to the original
interrupted user instruction. interrupted user instruction.
@ -324,7 +312,7 @@ test0() works.</b>
<li>Have <tt>usertrap</tt> save enough state in <li>Have <tt>usertrap</tt> save enough state in
<tt>struct proc</tt> when the timer goes off <tt>struct proc</tt> when the timer goes off
that <tt>sigreturn</tt> can correctly return to the that <tt>sigreturn</tt> can correctly return to the
interrupted code. interrupted user code.
<li>Prevent re-entrant calls to the handler----if a handler hasn't <li>Prevent re-entrant calls to the handler----if a handler hasn't
returned yet, the kernel shouldn't call it again. returned yet, the kernel shouldn't call it again.