The goal of this exercise is to design and implement an user-level thread package. Threads created by this package are not visible to the underlying OS, so the scheduler itself must run within the user process.
The user-level thread package must implement, at least, the following interface:
int init(void)
int create(void (* entry)(int), int arg)
entry
,
which is a pointer to a plain function taking an integer as
argument. The function returns an identifier for the created
thread in case of success and "-1" in case of failure.
int join(int tid, int * status)
tid
to exit,
returning it's return value in status
. In case of
success, this function returns "0", otherwise, "-1".
void exit(int status)
join
.
void yield(void)
int getid(void)
The user-level thread package must feature a thread scheduler implementing a police of choice plus a back-end mechanism enforcing a round-robin police with a quantum of 100 milliseconds. For example, if static priorities are chosen as the main police, then the thread creation primitive must be extended to feature a priority and threads are scheduled based on that value. Nevertheless, after a quantum, the scheduler must be activated to validate the current selection, thus enforcing round-robin for same-priority threads.
In theory, any POSIX.1 compliant system should
deliver the basic functionality needed to implement the proposed
thread package at user-level. The key issues, i.e., context
switching and timing can be implemented based on LIBC functions
setjmp
and longjmp
and on the system
calls setitimer
and signal
.
setjmp
saves the stack context/environment.
longjmp
can restore the stack context/environment later. In
this way, longjmp
"returns" to the state of the program
when setjmp
was called.
The return value from setjmp
indicates whether control
reached that point normally (returns 0) or from a call to
longjmp
(returns a value other than 0).
if(setjmp(old_context) == 0)
longjmp(new_context, 1);
else
return;
setcontext
, getcontext
, makecontext
and swapcontext
). These functions are available on recent versions of the
Standard C library. Remeber, man
command is your friend.setitimer
sets value of an interval timer (QUANTUM)
which the SIGALRM signal will be generated. In addition, it is possible to
install a new signal handler ("scheduler") for the signal SIGALRM through of
the function signal
.
struct itimerval time;
time.it_interval.tv_sec = 0;
time.it_interval.tv_usec = 100000;
time.it_value.tv_sec = 0;
time.it_value.tv_usec = 100000;
signal(SIGVTALRM, scheduler);
setitimer(ITIMER_VIRTUAL, &time, NULL);
Download source code