In this assignment you will implement a simplified version of many-to-one user level threads in form of a library called Simple Threads™.
Before you continue make sure you’ve read the page and self-study slides about implementing threads.
You should already have cloned the module-4
repository.
New files have been added to the module-4
GitHub repository. From the terminal,
navigate to the module-4
directory
and pull the new files from the GitHub
repository.
$ git pull
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.
In module-4/examples/src/contexts.c
you find an example program demonstrating
how to create and manipulate execution contexts.
Study the source. To compile, navigate to module-4/examples
in the terminal, type make
and press enter.
$ make
To run:
$ ./bin/contexts
In module-4/higher-grade/src
you find the following files.
Study the source and pay attention to all comments.
In the terminal, navigate to the module-4/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 ====
For grade 4 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.
For grade 5 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.
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.
In module-4/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.