CS611
Programming Assignment 3
Spring 1999


Implement a simple threads package for the Alpha 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 2048 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 75% of the points for this assignment.

The other 25% of the points will be given for implementing the following primitives:

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());

Your implementation should be performed using both C and Alpha assembler. Use C for as much of the code as possible and only use assembler when necessary.

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 code should be submitted for grading from alberti (or hopper or christa). To turn in this assignment, type:
~cs611/bin/submit prog3 <list of files to submit>

Do not turn in any non-Ascii files (i.e. no object files, no executable files, etc.).

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

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

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


Last modified on February 16, 1999.

Comments and questions should be directed to pjh@cs.unh.edu