CS611
Spring 2002
Programming Assignment 5
Due Sunday April 14


Implement a preemptive threads package for the Linux Intel IA-32 architecture.

The two fundamental primitives that you should implement first are:

long thread_create(void (*start_func)(void*), void* info);
void thread_yield(void);

The thread_create primitive is passed two parameters. The first parameter is a function that should be executed by the newly created thread. The second parameter is a parameter to be passed to that function.

The thread_create primitive returns 0 if it cannot create the thread. Otherwise it returns a non-zero thread identifier that can be passed to other primitives to control the thread (see below).

When a thread is created, it should be given a stack of 16384 bytes.

A FIFO list of active threads should be maintained. This list should be initialized upon the first call to a thread primitive and should initially contain the "main" thread, the thread of control created "automatically" when the process was created. When thread_create is called, the newly created thread should be placed on the end of the list. Note: a newly created thread does not start executing immediately. Rather it is simply placed at the end of the list of active threads.

When thread_yield is called, the currently executing thread should be moved to the end of the list of active threads and the thread that is now at the front of the list should become the thread that is now executing. If there is only one active thread, then that thread continues executing.

There is no status associated with a call to thread_yield (i.e. it must succeed) so the primitive returns nothing.

When the main thread exits, then the process exits and all created threads are therefore terminated. When a created thread returns from its given function, then the thread is terminated, it is removed from the list of active threads, and any associated memory should be freed.

Your implementation of thread_create and thread_yield must be done first and will be worth 50 points for this assignment.

An additional 25 points will be given for implementing the following primitives (each of these primitives is equal weight):

long thread_suspend(long thread_id);
long thread_continue(long thread_id);
long thread_kill(long thread_id);
long thread_self(void);

The thread_suspend primitive puts the specified thread in a suspended state. That is, the thread will not execute again until its id is passed to a call to thread_continue. The thread_suspend primitive returns 0 if the thread_id is invalid; otherwise a 1 is returned. Note that it is not an error for a suspended thread to be suspended again. This has no effect but it is not an error.

Note also that a thread can suspend itself. This will require that another thread (the next one in the FIFO list of active threads) be made the currently executing thread. If the thread being suspended is the only active thread, then an error message should be printed to stderr and the program should be halted (call exit(-1)).

The thread_continue primitive moves a suspended thread to the end of the FIFO list of active threads. If the thread_id is invalid or the thread is not suspended, then the primitive returns 0; otherwise it returns 1.

The thread_kill primitive removes a thread from the system (and frees any associated memory). The thread can be either active or suspended. However, the main thread cannot be killed (but it can be suspended). (The user should use exit() instead.) If the thread_id is invalid or indicates the main thread, then the primitive returns 0; otherwise it returns 1.

Note that a thread can kill itself. This will require that another thread (the next one in the FIFO list of active threads) be made the currently executing thread. If the thread being killed is the only active thread, then an error message should be printed to stderr and the program should be halted (call exit(-1)).

The thread_self primitive returns the thread id for the currently executing thread. For example, a thread could kill itself by executing: thread_kill(thread_self());

An additional 25 points will be awarded if your implementation can support preemptive scheduling of the threads. This means that thread_yield will be called by the handler for a timer signal. When the thread_create primitive is initially called, initialize an interval timer using the setitimer function (see man setitimer). Request a virtual timer (ITIMER_VIRTUAL) and use a time slice of 10 milliseconds.

Specify a handler for the virtual timer alarm signal (SIGVTALRM) using the sigaction function (see man sigaction). You should use the SA_NODEFER flag to allow multiple handlers to be alive at the same time.

With preemptive scheduling you must be careful since now there will be asynchronous events. That is, the timer may go off at any time. For instance, consider a user program calling thread_yield and then a timer signal is generated. What might go wrong? You will need to develop a technique for disabling timer signals (or ignoring them) when you are in critical sections of code.

Your implementation should be performed using both C and Intel IA-32 assembler. Use C for as much of the code as possible and only use assembler when necessary. Place the C code in a file called thread.c and place the assembler code in a file called thr_asm.s.

The directory ~cs611/public/prog5 contains test programs that you can link with your code. Only these test cases will be used for grading this assignment.

Your program will be graded primarily by testing it for correct functionality. However, you may lose points if your program is not properly structured or adequately documented. Remember that with assembler code documentation is even more important than with C programs.

Your assignment should be submitted for grading from a CIS Alpha machine (e.g. cisunix.unh.edu). Submit just two files, thread.c and thr_asm.s. To turn in this assignment, type:
~cs611/bin/submit prog5 thread.c thr_asm.s

Do not turn in any other files!

Submissions can be checked by typing:
~cs611/bin/scheck prog5

To receive full credit for the assignment, you must turn in your files prior to 8am on Monday April 15. Late submissions will be accepted at the penalty of 5 points per day up to one week late.

Remember: as always you are expected to do your own work on this assignment.


Last modified on January 10, 2002.

Comments and questions should be directed to hatcher@unh.edu