Simple Threads

Optional assignment for higher grade (3 points)

In this assignment you will implement a simplified version of many-to-one user level threads in form of a library that we give the name Simple Threads.

Preparations

Before you continue make sure you’ve read the implementing threads page. Among the slides in Studium you also find self study material about implementing threads.

Git

You should already have cloned the threads-and-synchronization repository.

Manage execution contexts

The ucontext.h header file defines the ucontext_t type as a structure that can be used to store the execution context of a user-level thread in user space. The same header file also defines a small set of functions used to manipulate execution contexts. Read the following manual pages.

Example

In examples/src/contexts.c you find an example program demonstrating how to create and manipulate execution contexts. Study the source. To compile, navigate to the examples directory in the terminal, type make and press enter.

make

To run:

./bin/contexts

Get started

In higher-grade/src you find the following files.

sthreads.h
Header file specifying the Simple Threads API.
sthreads.c
Implementation of the Simple Threads API.
sthreads_test.c
A program used to test the Simple Threads API.

Study the source and pay attention to all comments.

First compile and test run

In the terminal, navigate to the higher-grade directory. Use make to compile.

make

Run the test program.

./bin/sthreads_test

The program prints the following to terminal and terminates.

==== Test program for the Simple Threads API ====

Cooperative scheduling (2 points)

For grade 2 points you must implement all the functions in the Simple Threads API except done() and join. This includes cooperative scheduling where threads yield() control back to the thread manager.

The test program’s main() thread and all threads created by main() share a single kernel-level thread. The threads must call yield() to pass control to the thread manager. When calling yield() one of the ready threads is selected to execute and changes state from ready to running. The thread calling yield() changes state from running to ready.

Non-terminating threads

For grade 4 you may assume the main thread and all other threads are non-terminating loops.

Preemptive scheduling (3 points)

For 3 points, you must also implement the done() and join() functions in the Simple Threads API. In addition to cooperative scheduling with yield() you must also implement preemptive scheduling.

If a thread doesn’t call yield() within its time slice it will be preempted and one of the threads in the ready queue will be resumed. The preempted thread changes state from running to ready. The resumed thread changes state from ready to running.

Timer

To implement preemptive scheduling you need to set a timer. When the timer expires the kernel will send a signal to the process. You must register a signal handler for the timer signal. In the signal handler you must figure out a way to suspend the running thread and resume one of the threads in the ready queue.

Timer example

In examples/src/timer.c you find an example of how to set a timer. When the timer expires the kernel sends a signal to the process. A signal handler is used to catch the timer signal.