CS520
Fall 2017
Laboratory 7
Friday October 20
The lab must be submitted prior to 12noon on Sunday October 22.
This is a difficult lab.
I will discuss it in detail in class on Thursday October 19.
If you would like to start earlier, watch the video,
Implementing Threads on the Intel 64
(29 min,
slides).
The goal for this lab is to complete the thread_create and the
thread_yield functions:
- Define a C struct for the Thread Control Block (TCB),
which contains the following members:
- members to store the saved contents of the rsp, rbx, r12, r13,
r14 and r15 registers.
- a pointer to a TCB, to allow TCBs to be linked together.
- members to store values to be used to initialize the rdi and rsi
registers when a thread is created and then started.
- a pointer to the base of the thread's stack so it can be deallocated.
- Create a "ready list", a linked list of all the TCBs for threads
that are ready to run.
The first TCB on the list should be the currently running thread.
I recommend implementing the ready list by using two global static pointers
to TCBs, one to point to the head of the list and one to point to the
tail of the list.
Initialize these two pointers to NULL.
- Write an Intel 64 assembly language routine to be used by
thread_yield in order to save the state of the current thread and
to restore the state of the thread to run next:
- The function should begin with the two instructions that all
"good" Intel 64 functions begin with: push the current frame
pointer (rbp) onto the top of stack, and establish the new frame pointer
to point to the top of the stack.
- Next check if the function's first parameter (which will be in rdi)
is null (zero).
If so, branch over the next several instructions that save the
save the state of the current thread.
- Save the state (rsp, rbx, r12, r13, r14, r15) of the current thread
into the TCB pointed to by the first parameter (rdi).
This will be done by a sequence of "movq" instructions, e.g.
movq %rsp, 0(%rdi).
Note that each value will be stored at a particular offset into
the struct.
In the "movq" instruction given, it is assumed that the rsp register
is stored first in the TCB struct, which will be at offset 0.
Be sure that the offsets you use in assembly language align with
how you declared the C struct.
- Restore the state of the thread to run next from the TCB pointed
to by the second parameter (rsi).
This will be done by a sequence of "movq" instructions, e.g.
movq 0(%rsi), %rsp.
Also move values from the rdi and rsi TCB slots into rdi and rsi.
Be sure you set the rsi register last.
- The function should end with the two instructions that all "good"
Intel 64 functions end with: set the frame pointer (rbp) by
popping a value from the top of the stack, and then a return
instruction.
- Write the thread_start C function. The exact C code is:
void thread_start(void (*work)(void *), void *info) {
work(info);
thread_cleanup();
}
- Write the thread_yield C function:
- If the ready list is empty, malloc a TCB for the main thread
and insert it to the ready list.
- Rotate TCBs on the ready list: first (current running thread)
becomes last and second (next to run) becomes first.
- Call the assembly language routine to save the state of the
current running thread into its TCB and to restore the state
of the thread to run next from its TCB.
- Write the thread_create C function:
- If the ready list is empty, malloc a TCB for the main thread
and insert it to the ready list.
- Use malloc to allocate a TCB and put it on the end of the ready list.
- Use malloc to allocate a stack.
Save the base address of the stack in the TCB so it can be freed later.
- If either malloc fails, return NULL from thread_create.
- Initialize the TCB and the stack so that the thread, when it is yielded
to, will execute the thread_start function:
- put the thread_create's arguments into the rdi and rsi
slots of the TCB.
- put the address of the third-to-last quadword in the stack into
the rsp slot of the TCB.
- put the address of the thread_start function into the
second-to-last quadword in the stack.
- Return the pointer to the TCB as the function's return value.
- Write the thread_cleanup C function:
- Remove the TCB from the front of the ready list.
- Free the stack for the last thread that called thread_cleanup.
- Remember the pointer to the base of the stack for the current
thread so that it can be freed at the next call to thread_cleanup.
- Free the TCB that was removed from the front of the ready list.
- Call the assembly language routine that saves/restores thread
state, passing NULL for its first parameter, and passing as the
second parameter the address of the TCB now on the front
of the ready list.
I will test with the following files
(available in ~cs520/public/prog4):
- test1.c
- test2.c
- test3.c
- test4a.c
- test4b.c
- test5.c
Since this is a difficult lab, partial credit will be awarded for
making an "honest attempt" at each item in the above list of tasks
to be completed.
If your code does not pass any of the above tests, we will review
your source code to see if you have made a reasonable attempt
to complete each task.
The code review code for each task will be worth 10 points, for
a total of 70 points.
Executing tests will be worth 30 additional points.
If you successfully execute test1.c, you will be automatically
given the 70 points for an honest attempt.
Turn in this laboratory by typing:
% ~cs520/bin/submit lab7 thread.c thr_asm.s thread.h
Submissions can be checked by typing:
% ~cs520/bin/scheck lab7
Remember that there are no late submissions of labs.
Submit what you have prior to 12noon on Sunday October 22.
Be careful: one minute late is late.
Last modified on October 11, 2017.
Comments and questions should be directed to
pjh@cs.unh.edu