diff options
author | Robert Morris <[email protected]> | 2019-08-03 07:12:00 -0400 |
---|---|---|
committer | Robert Morris <[email protected]> | 2019-08-03 07:12:00 -0400 |
commit | deec67f05db8377dc912c33ff910002364f9199a (patch) | |
tree | 2e5ab35f75b1ef7ed73393f58b538fc40b7daf98 | |
parent | fdea26548977d9a9b188c90ebe6e89c1cc1a8dfa (diff) | |
download | xv6-labs-deec67f05db8377dc912c33ff910002364f9199a.tar.gz xv6-labs-deec67f05db8377dc912c33ff910002364f9199a.tar.bz2 xv6-labs-deec67f05db8377dc912c33ff910002364f9199a.zip |
alarm stuff
-rw-r--r-- | labs/syscall.html | 126 |
1 files changed, 57 insertions, 69 deletions
diff --git a/labs/syscall.html b/labs/syscall.html index 835e510..662641c 100644 --- a/labs/syscall.html +++ b/labs/syscall.html @@ -7,10 +7,10 @@ <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 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> @@ -119,7 +119,6 @@ interrupts. <p> 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> #include "kernel/param.h" #include "kernel/types.h" @@ -143,12 +142,12 @@ void test0() { int i; printf(1, "test0 start\n"); - alarm(2, periodic); + sigalarm(2, periodic); for(i = 0; i < 1000*500000; i++){ if((i % 250000) == 0) write(2, ".", 1); } - alarm(0, 0); + sigalarm(0, 0); printf(1, "test0 done\n"); } @@ -171,7 +170,7 @@ void test1() { printf(1, "test1 start\n"); j = 0; - alarm(2, periodic); + sigalarm(2, periodic); for(i = 0; i < 1000*500000; i++){ foo(i, &j); } @@ -185,55 +184,53 @@ void test1() { 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, -and then spins for a while. After you have implemented -the <tt>sigalarm()</tt> system call in the kernel, -<tt>alarmtest</tt> should produce output like this for <tt>test0</tt>: +and then spins for a while. +You can see the assembly +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> $ alarmtest -alarmtest starting -.....alarm! -....alarm! -.....alarm! -......alarm! -.....alarm! -....alarm! -....alarm! -......alarm! -.....alarm! -...alarm! -...$ +test0 start +...................................................alarm! +.............................................................alarm! +(repeated many times) +test0 done +test1 start +..alarm! +..alarm! +..alarm! +(repeated many times) +test1 done +$ </pre> -<p> <p> -(If you only see one "alarm!", try increasing the number of iterations in -<tt>alarmtest.c</tt> by 10x.) +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 process's alarm interval expires, the process executes - the handler. How can you do that? You will need to understand in - detail how system calls work (i.e., the code in kernel/trampoline.S - and kernel/trap.c). Which register contains the address where - system calls return to? + the handler. How can you do that? You will need to understand + how system calls work (i.e., the code in kernel/trampoline.S + and kernel/trap.c). Which register contains the address to which + system calls return? -<p>Your solution will be few lines of code, but it will be tricky to - write the right lines of code. The most common failure scenario is that the - 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. +<p>Your solution will be only a few lines of code, but it may be tricky to + get it right. -<h3>Test0: invoke handler</h3> +<h3>test0: invoke handler</h3> -<p>To get started, the best strategy is to first pass test0, which - will force you to handle the main challenge above. Here are some - hints how to pass test0: +<p>Get started by modifying the kernel to jump to the alarm handler in +user space, which will cause test0 to print "alarm!". Don't worry yet +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> <li>You'll need to modify the Makefile to cause <tt>alarmtest.c</tt> @@ -268,7 +265,7 @@ in <tt>usertrap()</tt>; you should add some code here. if(which_dev == 2) ... </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 function might be 0 (e.g., in alarmtest.asm, <tt>periodic</tt> is at address 0). @@ -279,41 +276,32 @@ use only one CPU, which you can do by running make CPUS=1 qemu </pre> -<li><b>XXX we need to somehow convey what it is they don't - 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> +<li>You've succeeded if alarmtest prints "alarm!". </ul> <h3>test1(): resume interrupted code</h3> -<p><b>XXX it is surprising that test0() appears to work -perfectly, even though something is seriously wrong -with the way periodic() returns. we should recognize -that something odd is happening, maybe ask them to think -about it, and hint or say why they are not done even though -test0() works.</b> - -<p>Test0 doesn't test whether the handler returns correctly to - the user instruction that was interrupted by the timer. - The previous section didn't require you to get this right. - If you didn't, test0 will probably succeed anyway, but - test1 will likely fail (the program crashes or the program - goes into an infinite loop). - Another challenge is that the register contents need to be - correct when control returns to the interrupted user instruction. +Chances are that alarmtest crashes at some point after it prints +"alarm!". Depending on how your solution works, that point may be in +test0, or it may be in test1. Crashes are likely caused +by the alarm handler (<tt>periodic</tt> in alarmtest.c) returning +to the wrong point in the user program. + +<p> +Your job now is to ensure that, when the alarm handler is done, +control returns to +the instruction at which the user program was originally +interrupted by the timer interrupt. You must also ensure that +the register contents are restored to values they held +at the time of the interrupt, so that the user program +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). There are - several ways to restore the registers; one convenient plan is to add another - system call <tt>sigreturn</tt> that the handler calls when it is + 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 interrupted user instruction. @@ -324,7 +312,7 @@ test0() works.</b> <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 - interrupted code. + interrupted user code. <li>Prevent re-entrant calls to the handler----if a handler hasn't returned yet, the kernel shouldn't call it again. |