Project 6: xv6 Threads
Important Dates
Questions about the project? Send them to 537-help@cs.wisc.edu .
Due: Monday, 4/25, by whenever.
Notes
This project can be done in either by yourself or in a team of size
two.
Overview
In this project, you'll be adding real kernel threads to xv6. Sound like
fun? Well, it should. Because you are on your way to becoming a real kernel
hacker. And what could be more fun than that?
Specifically, you'll do three things. First, you'll define a new system
call to create a kernel thread, called clone() . Then, you'll use
clone() to build a little thread library, with a thread_create() call
and lock_acquire() and lock_release() functions. Finally, you'll
show these things work by writing a test program in which multiple threads are
created by the parent, and each insert items into a thread-safe linked list
that you will write. That's it! And now, for some details.
Details
Your new syscall should look like this: int clone(void *stack, int
size) . It does more or less what fork() does, except for one major
difference: instead of making a new address space, it should use the parent's
address space (which is thus shared between parent and child). You might also
notice a single pointer is passed to the call, and size; this is the location
of the child's user stack, which must be allocated before the call to
clone is made. Thus, inside clone() , you should make sure that when you
return, you are running on this stack, instead of the stack of the parent.
As with fork() , the clone() call returns the pid of the child
to the parent, and 0 to the newly-created child thread.
Your thread library will be built on top of this, and just have a simple
thread_create(void *(*start_routine)(void*), void *arg) routine. This
routine should use clone() to create the child, and then call
start_routine() with the argument arg .
Your thread library should also have a simple spin lock. There should be a
type lock_t that one uses to declare a lock, and two routines
lock_acquire(lock_t *) and lock_release(lock_t *) , which acquire and
release the lock. The spin lock should use x86 atomic exchange to built the
spin lock (see the xv6 kernel for an example of something close to what you
need to do). One last routine, lock_init(lock_t *) , is used to
initialize the lock as need be.
To test your code, you should build a simple program that uses
thread_create() to create some number of threads; each thread should, in a
loop for a fixed number of times, add an element to a shared linked list of
integers. For example, if a thread is told to run for 10 iterations through a
loop, it should add an element for 0, then 1, then 2, and so on to the
list. If there are two threads running, they should each do this in
parallel. The linked list should be thread safe, grabbing a lock each time an
element is being added to the list, and letting it go when done. At the end,
the main thread should call wait() (repeatedly, once per child) to wait
for all the children to complete; at this point, the main thread should add up
all of the values of the elements on the list, and print out a final value.
The command line arguments for this program are thus:
prompt> main numberOfThreads loopCount
Have fun!
The Code
The code (and associated README) can be found in
~cs537-1/ta/xv6/ . Everything you need to build and run and even debug the
kernel is in there, as before.
You may also find the following readings about xv6 useful, written by the
same team that ported xv6 to x86: chapters 0 ,
1 ,
2 ,
3 ,
4 ,
5 ,
6 ,
7 ,
8 ,
9 .
All of these can be found off the
xv6 site .
Particularly useful for this project: Chapters 2, 4, 5.
You may also find this book useful:
Programming from the Ground Up . Particular attention should be paid to the
first few chapters, including the calling convention (i.e., what's on the
stack when you make a function call, and how it all is manipulated).
Testing
Unlike before, we will be grading this project by examining your code and
reading a write-up describing the changes you made, as well running the list
test as described above. The write-up should be short (a few pages at most) and
concise. You should also describe how you tested your code, to convince us
(and yourselves) that it works!
Handing It In
Use the p6 directory for your handin. If working as a team of two, please
handin the material in ONE directory, with a README that clearly
indicates the names and CS logins of the team members. Also, create a soft
link to the handin directory of the other team member with the name
partner ; for example, if the two partners are named joe and jane, and you
turn in the project in jane's p5 directory, you should go into jane's p5
directory and type ln -s ~cs537-1/handin/joe/p5 partner to create the
soft link.
Turn in a writeup, called p6.pdf , which describes the changes and all
the stuff you have done to build and test your kernel.
Turn in all files that you have changed or added (.c and .h files, and
possibly a modified Makefile). Thus, we should be able to take your handed in
files, add the rest of the source code, and build and run your kernel and any
tests you have turned in.
|