still working on adding a system call task -but it still possible to get started on this taks using pointers.
Project 5: Semaphore - SUFiX -
Assignment Day | October 28, 2009 (Wednesday - midnight) |
Due Date | November 11, 2009 (Wednesday 5 PM, but no penalty until the start of November 12). |
Collaboration Policy - Read Carefully
You may work on this project with a partner, and you are encourage to discuss the assignment with other students or teams on the email list. You may consult (but not copy) any outside resources you including books, papers, web sites and people (but no penguins or sea urchins).
All team members need to provide the name of their partner in their partner.txt file (and say "none" if there is no partner).
If you use resources other than the class materials, indicate what you used along with your answer.
You have probably guessed it by now - every project will have a similar paragraph to the one above but with slight variations, of-course.
If you work on your own - you will get a 5% bonus provided that your base grade is above 60%). As this will require more effort.
Lessons to date: 1) Participate on the google MINIX group, it is a fantastic resource, 2) Use google - you won't get penalized - it is a win-win tool 3) Use the class list, but to get a reply - be courteuous and outline what resources you have tried before posting, e.g., I tried searching on google for "add a server to MINIX", I posted on the google MINIX but I did not get a reply 4) MISC - IF you do work on a team - and get stuck - try to use your partner's set-up, backup frequently - your kernel will crash - and it will crash often.
Objective:
The main objectives for this project are:
- Get more experience with a real operating.
- Understand the structure of a microkernel.
- Understand how a system call works.
- Understand synchronization.
The latest version of this project is borrowed from Prof. Christopher Kruegel's CS 170 Course at UC, Santa Barbara. I have also noted that there are helpful hints on this project on the MINIX google group - so you might want to check that out.
Tutorial / References
How to implement a system call:http://www.phien.org/ucdavis/ta/ecs150-f03/syscall.html http://www.cis.syr.edu/~wedu/seed/Documentation/Minix3/How_to_add_system_call.pdfhttp://fixunix.com/minix/255067-add-system-call.htmlHow to implement a semaphore service:http://www.usenix.org/publications/login/2006-04/openpdfs/herder.pd |
If you find other resources please post links on the mailing list for the class. |
Background:
And it doesn't hurt to mention this again:
As previously mentioned this project will teach you how to experiment with a real operating system kernel(s)- and as a consequence you will learn to work in such a way that deals with a computer crashes (well not quite since we are working in a virtual machine) and / or end up with an OS that doesn't work.We suggest that you manage multiple kernels, and always have access to at least one working kernel. Back up your work frequently and work in small incremental steps. Incremental steps is very important. A step could be as small as one line of code, or changing the value of an assignement.
Basics:
This center piece of this project is to add a new synchronization "service" to MINIX. This service provides synchronization using semaphores and isimplemented as a "system service", similar to the process manager (PM) or the file system server. There are three tasks in the project and TWO of the taks can be completed independently. The three tasks are:
- Implement a system call in MINIX,
- Add a semaphore "service" to MINIX (this uses system calls
so it builds on the first task). - Write a C program that use the semaphore service above (for partial credit you may complete a pre-curser of this program using semaphores on atlas or odin).
This project is worth 150% - so 1 1/2 project (1/2 project for each task).
Details:
Task 1: Provide System Calls
Here are some pointers for task one:
http://www.phien.org/ucdavis/ta/ecs150-f03/syscall.html
http://www.cis.syr.edu/~wedu/seed/Documentation/Minix3/How_to_add_system_call.pdf
http://fixunix.com/minix/255067-add-system-call.html
Your first task is to implement the tutorial (and steps) outlined in the first link, link 1 above (this one: here), and implement the system call: do_foo.
You need to make sure that you port it to your version of MINIX, i.e., version 3.1.4.
Task 2: Provide a semaphore synchronization service
Task TWO builds on task one as it requires system calls. Here the real challenge, is two fold: (1) is to add another 'service' to MINIX (like the file or process "services") that is part of the boot image and starts up during booting and (2) is process management that wakes and put processes to sleep. The semaphore service includes implementing appropriate semaphore messages such as SEMA_UP, SEMA_DOWN, SEMA_INIT and SEMA_RELEASE (more on this in details below).
The service you are providing is to add semaphore support to MINIX. Currently, MINIX lacks a mechanism to synchronize different processes. The goal for this task is to change this limitation and write a semaphore service. This semaphore service should be implemented as a system service, similar to the process manager (PM) or the file system. That is, your semaphore service should be a service that is part of the boot image and automatically start when the system is booted. This semaphore service should understand four different messages: SEMA_INIT, SEMA_RELEASE, SEMA_DOWN, and SEMA_UP.
Task 1 Extension (System Calls)
Of course, user programs are not supposed to build these messages directly. Instead, and similar to task 1, you are supposed to write POSIX library wrapper functions that create the appropriate messages with the right number of parameters.
You'll also have to declare the functions in an appropriate header file (e.g. /usr/src/include/unistd.h) and provide the wrapper functions (take a look at /usr/src/lib/syslib). Note that you need to rebuild the libraries by doing a "make libraries" inside /usr/src/tools.
In the following, the semantics of these four library functions (and the corresponding messages that they create) are described below:
- int sema_init(int semaphore_number, int start_value): This function creates a SEMA_INIT message that is sent to the semaphore service. The parameter semaphore_number is an integer that specifies the index of the semaphore that should be initialized. Your service is supposed to support 10 different semaphores, thus, this argument must be a number between 0 and 9. The parameter start_value specifies the initial value for the semaphore. It can be an arbitrary integer value. Typically, for a mutex, this value would be +1. Once a semaphore has been initialized, it is considered active. Calling sema_init on an active semaphore is an error. You can only initialize inactive semaphores. Make sure to return an error code to the calling function in case an active semaphore is initialized, or in case on an invalid argument. Of course, initially, all semaphores are inactive.
- int sema_down(int semaphore_number): This function creates a SEMA_DOWN message that is sent to the semaphore service. This call can only be invoked for an active semaphore. Calling it on an uninitialized semaphore leads to an error. This function implements the standard semantics of semaphore.down(). That is, the call decrements the counter of the corresponding semaphore by one. When the counter (after the decrement) has a value of < 0, then the calling process should be put to sleep (waiting in the queue that corresponds to the semaphore). The value of the parameter semaphore_number must be between 0 and 9.
- int sema_up(int semaphore_number): This function creates a SEMA_UP message that is sent to the semaphore service. This call can only be invoked for an active semaphore. Calling it on an uninitialized semaphore leads to an error. This function implements the standard semantics of semaphore.up(). That is, the call increments the counter of the corresponding semaphore by one. When there is at least one processes waiting (sleeping) in the queue, the first process that was put to sleep should be woken up (i.e., sleep and wake up is FIFO). The value of the parameter semaphore_number must be between 0 and 9.
- int sema_release(int semaphore): This function creates a SEMA_RELEASE message that is sent to the semaphore service. This call can only be invoked for an active semaphore. Calling it on an uninitialized semaphore leads to an error. The purpose of this function is to release an active semaphore and put it back into the inactive state. The value of the parameter semaphore_number must be between 0 and 9. This function fails when there are currently processes waiting in the queue of the semaphore that should be released.
For the first challenge, which is to make a system service that is included into the boot image of Minix, it makes sense to look at the code of a simple system service such as DS (which can be found under /usr/src/servers/ds). You can, for example, copy the files that are in this directory into a new directory (such as /usr/src/servers/ss). Then, update the makefiles appropriately to make sure that your new server is compiled. Finally, look at the code that you just copied. You will see that in main.c, there are routines to initialize and exit the server, routines to get and process messages (the loop in the main function), and code to dispatch different messages to different routines. Many of the functions that do the actual work are in store.c. You will probably want to adapt this code so that you keep the main loop that processes messages, but you invoke different semaphore routines, depending on which message is sent by a user program.
The four messages that can be sent to the semaphore service can be defined in /usr/src/include/minix/com.h. Just check out how other messages such as those to the data store server (DS) are defined. Also, you might want to add your service to the list of system services (check for DS_PROC_NR).
Another step to become a full-fledged system service is to inform the kernel that the boot image has now one additional process. To this end, check out the image[] array in /usr/src/kernel/table.c. Moreover, make sure that the permissions are set so that user processes can send messages to your new semaphore service.
Finally, you have to update the makefile that is responsible for creating the boot image and make sure that your new server is properly included. As you probably know by now, this makefile is located under /usr/src/tools.
At this point, you should check whether you have all the things in place to be able to send messages to your new service. That is, check whether a user program can use your new library wrapper functions (such as sema_init) to send messages to the new semaphore service, which hopefully is started during boot time as part of the boot image.
Once you are sure that you can send messages to your system service, it is time to implement the actual semaphore functionality. Recall that you need to be able to support 10 semaphores, each of which needs its own counter and queue for processes that sleep. For a nice discussion of how a semaphore service can be implemented, see the case study section of this article.
Once you your semaphore service in place, play around with user processes that initialize semaphores, call sema_down on them to sleep, and have them woken up by other processes that call sema_up.
Task 3: Provide a user appliction program
Now that we have semaphores available, we would like to use them to solve a simple synchronization problem. The problem is as follows:
You have been hired by the CS Division to write code to help synchronize a professor and his/her students during office hours. The professor waits until there are students around to ask questions; if there are students who want to ask questions, they must synchronize with each other and with the professor so that (i) only one person is speaking at any one time, (ii) each student question is answered by the professor, and (iii) no student asks another question before the professor is done answering the previous one. Each student asks a single question.
To solve this problem, you have to write two C programs, one called prof.c, which implements the actions of the professor, the other one called student.c, which implements the actions of the student. Note that there can be only one prof process, but multiple student processes running at the same time. You can assume that the prof process is started first, so you can add all (semaphore) initialization code there. Whenever it is the turn of a student to ask a question, print out "student: ask question\n" to standard output. Once a question is asked, the professor process should respond by printing out "prof: answer question\n". After that, the student is (hopefully) happy and leaves, printing "student: leaving room\n".
The prof and student processes must be synchronized such that the order requirements introduced above are met. That is, once a student prints out "student: ask question\n", the next printout must come from the professor process. That is, no other student process is allowed to "ask a question", and the student process that asked is not allowed to "leave the room" before the professor task has "answered the question". Make sure that the professor process sleeps for a few seconds (using the call sleep(n)) before "answering a question" to add some delay.
As an example, assume that there is one professor process running. Then, three student processes are started simultaneously. The output to the console should be:
student: ask question
prof: answer question
student: leave room
student: ask question
prof: answer question
student: leave room
student: ask question
prof: answer question
student: leave room
Write the code for the prof and the student programs, making sure that the necessary synchronization code is in place to ensure the required order of interaction.
Hints
- START EARLY!
- You should start with your design, and check it over.
- Experiment! You're running in an emulated system—you can't crash the whole computer (and if you can, let us know...).
- You may want to edit your code outside of MINIX (using
your favorite text editor) and copy it into MINIX to
compile and run it. This has several advantages:
- Crashes in MINIX don't harm your source code (by not writing changes to disk, perhaps).
- Most OSes have better editors than what's available in MINIX.
- Use RCS to keep multiple revisions of your files. RCS is very space-efficient, and allows you to keep multiple "coherent" versions of your source code and other files (such as Makefiles).
- Here are some additional tips to get you started.
- Did we mention that you should START EARLY!
We assume that you are already familiar with makefiles and debugging techniques from your earlier project in this class or from courses such as CS 1730 or the UNIX tutorials held the first week of class by the department. If not (which is unlikely), this will be a considerably more difficult project because you will have to learn to use these tools as well.
You should do your design first, before writing your
code. To do this, experiment by inserting debugging print statements if it'll help. It
may be more fun
to just start coding without a design, but it'll
also result in spending more time than you need to on the
project.
IMPORTANT: As with all of the projects this semester, the key to success is starting early. You can always take a break if you finish early, but it's impossible to complete a 20 hour project in the remaining 12 hours before it's due....
Submitting:
Submitting:
|
Design Document:
Your design document should describe the design of your assignment in enough detail that a knowledgeable programmer could duplicate your work. This includes descriptions of the data structures you use, all non-trivial algorithms and formulas, and a description of each function including its purpose, inputs, outputs, and assumptions it makes about the inputs or outputs. A sample design document is available here.
Grading Criteria:
150 Total |
Component | Subcomponent | ||
90 | 60 | Design | 20 System Call |
Data Structures modified, added (detailed) |
Pseudo Code (include where: file/function name added/extended) | ||||
20 Semaphore Service |
||||
20 User Programs |
||||
30 | Compile/Run | As proof of concept demonstrates that “something” for each component compiles and runs (system call, semaphore service and prof.c/student.c apps). This is not expected to be a full fledge system (but enourages incremental development) | ||
20 | Full Fledge: System Call |
10 | Data structures – works! | |
10 | Functionality | |||
20 | Full Fledge: Semaphore Service |
10 | ||
10 | ||||
20 | Full Fledge: User Programs |
10 | ||
10 |