Operating Systems - Assignment 1
Operating Systems - Assignment 1
Introduction
Throughout this course we will be using a simple, UNIX like, teaching operating system
called xv6: http://pdos.csail.mit.edu/6.828/2011/xv6.html
The xv6 OS is simple enough to cover and understand within a few weeks yet it still
implements the important concepts and organizational structure of UNIX. To run it, you
will have to compile the source files and use the QEMU processor emulator (installed on
all CS lab computers).
Tip: xv6 was
(and
still
is)
developed
as
part
of
MIT’s
6.828
Operating
Systems
Engineering course. You can find a lot of useful information and getting started
tips there: http://pdos.csail.mit.edu/6.828/2011/overview.html
Tip: xv6 has a very useful guide. It will greatly assist you throughout the course
assignments: http://pdos.csail.mit.edu/6.828/2011/xv6/book-rev6.pdf
Tip: you may also find the following useful:
http://pdos.csail.mit.edu/6.828/2011/xv6/xv6-rev6.pdf
In this assignment, we will start exploring xv6 and extend it to support signals. The last
part will be devoted to writing a user program, which will test the OS modifications.
Begin by downloading our revision of xv6, from the os122 svn repository:
This will create a new folder called assignment1 which will contain all project
files.
Build xv6 by calling: make
Run xv6 on top of QEMU by calling: make qemu
Task
1:
warm
up
(“HelloXV6”)
This part of the assignment is aimed at getting you started. It includes an extension to
the xv6 shell – a simplistic implementation of the pwd command
Note that in terms of writing code, the current xv6 implementation is limited: it
does not support system calls you may use when writing on Linux and its
standard library is very thin.
Throughout all assignments, we will try to refrain from directing you to specific
parts of xv6. Although this may be a challenge by itself, we believe that in time it
will help you understand this OS better.
In this task you will replace the xv6 shell's current prompt (the
‘$’
symbol) with the full
path to the current working directory. This improved prompt is a simple form of a
productivity tool.
One can think of several different ways to implement this feature. The solution you will
follow in this task is a naïve one and will not involve important file system concepts
discussed at later parts of the course. It relies on the maintenance of a new variable
holding the string representation of the current working directory.
Start by finding the shell's source file. Look for the function which is in charge of
handling the change directory command (i.e., “cd”). Add a variable that will be used by
the shell to print the current working directory. This
variable’s
value
should
be
revised
after
each
call
to
“cd
<val>”
and
reflect
the
new
working
directory.
Assume that the maximal size of the prompt message does not exceed 256 characters.
Remember that the command may fail and illegal arguments or a single dot
(“cd
.”)
may
be
entered.
Next, locate the code lines that are in charge of printing the prompt to the user. Change
these lines so that the value of your new variable is printed instead.
After
invoking
“cd
temp” (and only if the temp folder exists) the prompt would change
to:
/temp/>
Tip: your solution should only affect the shell's source file.
Tip: don’t
forget
about relative changes to the working directory, such as “cd ..”.
Task 2: Signals framework
As seen in class, signals are a simple inter process form of communication currently not
implemented in xv6. In this part of the assignment, you will add the framework that will
enable the passing of signals from one process to the other. This implementation will
cover the basic features needed for a signals framework, and despite its resemblance to
the Linux framework it is far from being complete.
The first step towards meeting this goal is to
extend
the
‘proc’
struct located at proc.h
(line 61). The struct should contain a data word called signal each of whose bits
represents a currently unhandled (pending) signal. For example, when this
word’s
value
is 0x…2
(hex
representation
of
the
binary
word
00…0010)
then
this
process
received
a
signal whose identifier is 2. For simplicity, you may assume that your implementation
will never have to support more than 32 signals.
Note that this representation follows many modern operating systems where
multiple signals of the same type (having the same identifier) are ignored.
Each signal must also be associated with some action. To support this, add an array of 32
entries where every entry is a pointer to a function (accepting no arguments and
returning no value). By default all signals should be ignored, except for the ones defined
in task 3.
A process wishing to register a custom handler for a specific signal will use the following
system call which you should add to xv6:
This system call will register a new handler (handler) for a given a signal number
(signum). If successful, 0 is returned otherwise a -1 value is returned. The type
sighandler_t should be defined as:
Tip: Adding a system call requires some delicate work and proper registration. Be
sure to add changes to syscall.c, syscall.h, usys.S, user.h and sysproc.c
So far, we have allowed a process to prepare itself for an incoming signal. Next we will
add the ability to send a signal to a different process. Add the following system call:
Although
“kill”
is
the
standard
name
for
the
system
call
in
charge
of
sending
a
signal, it is already used in xv6 for terminating processes.
Given a process id (pid) and a signal number (signum), the sigsend system call will
send process pid the desired signal number. Upon successful completion, 0 will be
returned. A -1 value will be returned in case of a failure.
2.4 – getting the process to handle the signal:
Finally, you are to implement some mechanism which will make sure that a process
receiving a signal actually executes the relevant signal handler.
In your extension of xv6, a signal is handled (if at all) whenever the scheduler returns to
the process. That is, before the scheduler allocates a time slice to a process, it first checks
for sent signals to that process and if needed it updates the instruction pointer (and
stack pointer) by calling register_handler. This way, when the process receives its
time slice, the code for the signal handler is executed.
void
register_handler(sighandler_t sighandler)
{
char* addr = uva2ka(proc->pgdir, (char*)proc->tf->esp);
if ((proc->tf->esp & 0xFFF) == 0)
panic("esp_offset == 0");
/* update eip */
proc->tf->eip = (uint)sighandler;
}
The register_handler function is not native to xv6 and was added by the OS122
team to support the present assignment (you can find it in proc.c). The function locates
the
current
process’
stack
and
opens
a
new
frame.
It
must
also
update
the
old
instruction pointer so that when the new code (sighandler) is completed the process
normally resumes its execution.
The details of this function go beyond the scope of what you have seen so far and
require
better
understanding
of
xv6’s
memory
management.
Modify the fork system call so that a child process will have the same registered signal
handlers as his parent.
Support the following signals: SIGINT (id=0), SIGUSR1 (id=1), SIGUSR2 (id=2) and
SIGCHLD (id=3).
SIGUSR1 – reserved for user defined handlers, by default prints “SIGUSR1 <pid>”
SIGUSR2 – reserved for user defined handlers, by default prints “SIGUSR2 <pid>”
SIGCHLD – notifies
the
process’
parent
of
any
state
change.
Specifically, whenever a
process ends it should send a SIGCHLD to its parent.
Support the generation of a SIGINT signal to the currently executing process from the
keyboard.
This
signal
will
be
generated
whenever
the
user
presses
Ctrl+C
(‘^C’).
Notice that the signal could be sent when the current process sleeps, or even when the
shell awaits for the user's input. Find a way in which you would properly handle these
situations. procdump() -> console.c -> consoleintr
Tip: start by finding out where xv6 handles other special key combinations (e.g. ^p)
Task 4: Testing
In this section you will add a user application which tests the impact of your new signals
framework.
Similar to several built-in user space programs in xv6 (e.g., ls, grep, echo, etc.), you can
add your own user space programs to xv6.
Add a program called sanity. This program will fork 3 child processes and will then offer
the user the following simple command line interface.
The program should terminate after all child processes have terminated. Until then
these lines should be printed, allowing the user to test the signals framework.
Each child process will handle signal number 4 by printing “ouch <pid>”. While not
handling a signal each child process should run in an infinite loop, sleeping in each
iteration for half a second.
Tip: to add a user space program, first write its code (e.g., sanity.c). Next update
the Makefile so that the new program is added to the file system image. The
simplest way to achieve this is by modifying the lines right after “UPROGS=\”.
Tip: you can (and should!) read more about the make utility here:
http://www.opussoftware.com/tutorial/TutMakefile.htm
Tip: You have to call the exit system call to terminate a processes' execution.
Tip: The fork system call's return value will come in handy.
Submission guidelines
Make sure that your Makefile is properly updated and that your code compiles with
no warnings whatsoever. We strongly recommend documenting your code changes with
remarks – these are often handy when discussing your code with the graders.
Due to our constrained resources, assignments are only allowed in pairs. Please note
this important point and try to match up with a partner as soon as possible.
Submissions are only allowed through the submission system. To avoid submitting a
large number of xv6 builds you are required to submit a patch (i.e. a file which patches
the original xv6 and applies all your changes).
You may use the following instructions to guide you through the process:
Before creating the patch review the change list and make sure it contains all the
changes that you applied and noting more. Modified files are automatically detected by
svn but new files should be added explicitly with
the
‘svn
add’
command:
>svn add<filename>
>svn diff
Once you are ready to create a patch simply make sure the output is redirected to the
patch file:
Tip: although graders will only apply your latest patch file, the submission system
supports multiple uploads. Use this feature often and make sure you upload
patches of your current work even
if
you
haven’t
completed
the
assignment.
Finally, you should note that graders are instructed to examine your code on lab
computers only (!) - Test your code on lab computers prior to submission.
Take a deep breath. You are about to delve into the code of an operating system that
already contains thousands of code lines. BE PATIENT. This takes time!
I. Quota – as you well know, your CS share is limited. Before beginning your work
we recommend cleaning your home folders and running xv6 with no
modifications. If you still encounter problems you can try to work on freespace
(another file server). Note that unlike your home folders, freespace data is not
backed up – remember to back up your work as often as possible.
II. IDE auto-changes – we are aware that many of you prefer to work under
different IDEs. Note that unless properly configured these often insert code lines
or files which may cause problems at a later stages.
Although we do not limit you (in contrast we urge you to find the editor/IDE of
your liking) our advice is to use the powerful vi editor or GNU Emacs. If you
want an X application you can try running vim or gedit.
Another useful tip is to invoke grep often to quickly navigate through the code:
Debugging
You can try to debug xv6’s
kernel
with gdb (gdb/ddd is even more convenient). You can
read more about this here: http://zoo.cs.yale.edu/classes/cs422/2011/lec/l2-hw.
The CS lab computers should already contain both svn and qemu and if a host you are
working on does not please email [email protected] so that this is fixed ASAP.
Due to the large number of students taking this course we will only be able to support
technical problems that occur on the lab computers.
Having said that students wishing to work on their personal computers may do so in
several ways:
Tip: since xv6 may cause problems when shutting down you may want to consider
using the screen command.
screen make qemu-nox
Tip: use the default key bindings to toggle or even detach from a screen. Read
about them using:
man screen
2. Install Linux and QEMU on your own PC. Microsoft windows users can easily
install a dual boot (Windows-Linux) host with wubi:
http://www.ubuntu.com/desktop/get-ubuntu/windows-installer
Good Luck!