MC logo

F06 Assignment Specification

^  Dr. Bennet

Tswitch

Main Page
F06 Assignment
Download Library
CCSC '07 Paper

Clients for Tswitch

Save And Restore
Restack
Multiple Stacks

Clients for the F06 Assignment

Simple
Thread Demolition Derby
Graph Search
This is the specification for an assignment in Operating Systems for Fall 2006. Students used the tswitch library to implement the following non-preemptive threading interface. The implementation must create and destroy threads, and also suspend, resume and dispatch them while they exist. Data structures are required to support these operations. The interface is modeled after the Unix process creation primitives.
void th_init(void)

Initialize the package. The threaded program must call this function first. This allows the library to perform any needed initialization. One essential job of th_init is to record the initial thread, the one provided by the process running the program, so it can be scheduled along with the ones created by the package.

th_id_t th_fork();

This is modeled after the Unix fork() call for creating processes. A th_fork() call creates a new thread and returns twice, once in the original thread (the parent) and once in the new thread (the child). In the parent, it returns the thread id of the child. In the child, it returns the symbolic constant ARE_CHILD. The package must define ARE_CHILD such that it is not the identifier of any actual thread.

When a thread calls th_fork(), the library creates a child thread with a new stack containing a copy of the caller's topmost stack frame, including up to five parameters. The child thread is initially suspended, and th_fork() returns to the parent. The th_fork() will return in the child thread later, whenever it is selected to be run. The parent thread retains its same stack, and does not yield the CPU. If the child thread returns from the function which called th_fork(), it is equivalent to the thread performing a th_exit(0). A parent's return from this function behaves normally.

The return type, th_id_t, must be defined by the package. It is usually an integer or a void pointer, depending on the data structures used in the implementation.

th_yield(void)

The current thread yields use of the CPU itself. If there are no other ready threads, this returns immediately in the calling thread. Otherwise, the caller is placed at the end of the ready queue and the thread at the head of the queue receives control.

th_exit(int i);

The thread exits. Its return value is i, which can be recovered using th_wait.

th_kill(th_id_t t, int i);

The caller terminates the thread designated by t. It will be assigned the exit value given by i as though it had performed exit(i). A thread may terminate itself, which is equivalent to performing a th_exit. It is an error to kill a thread which has already terminated.

int th_wait(th_id_t t);

The calling thread waits for another thread indicated by t. The value of t must have been returned by an earlier th_fork. If that thread has already exited, th_wait immediately returns the exit value from the thread t. If not, the caller is suspended and the next ready thread is started. If there are no ready threads, the entire program exits with an error message. When t finishes, the waiting thread is made ready and moved to the end of the ready queue. Later, it will be resumed, and th_wait will return the exit value from t.

Each thread created by th_create should be th_waited on by exactly one other thread. If no one waits, then space allocated for the thread's stack may not be reclaimed. The results of having a thread th_waited by more than one other are undefined.

th_id_t th_me()

Return the id of the calling thread.

int th_stksize(int size)

Set the size in bytes of stack space allocated for all successive th_fork calls. It returns the old size. The symbolic constant DEF_STACK_SIZE gives the default size used when th_stksize has not been called.

The main thread that the process starts with cannot be terminated. Any attempt to do so is an error and should terminate the entire process. It does have a thread id (at least, after th_init is called), and other threads can wait on it. It will be a long wait, though.