CS520
Spring 2018
Laboratory 7
Friday March 23
The lab must be submitted prior to 12noon on Sunday March 25.


This is a difficult lab. I will discuss it in detail in class on Wednesday March 21. 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:

  1. Define a C struct for the Thread Control Block (TCB), which contains the following members:

  2. 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.

  3. 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:
    1. 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.
    2. 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 state of the current thread.
    3. 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.
    4. 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.
    5. 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.

  4. Write the thread_start C function. The exact C code is: void thread_start(void (*work)(void *), void *info) { work(info); thread_cleanup(); }

  5. Write the thread_yield C function:
    1. If the ready list is empty, malloc a TCB for the main thread and insert it to the ready list.
    2. Rotate TCBs on the ready list: first (current running thread) becomes last and second (next to run) becomes first.
    3. 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.

  6. Write the thread_create C function:
    1. If the ready list is empty, malloc a TCB for the main thread and insert it to the ready list.
    2. Use malloc to allocate a TCB and put it on the end of the ready list.
    3. Use malloc to allocate a stack. Save the base address of the stack in the TCB so it can be freed later.
    4. If either malloc fails, return NULL from thread_create.
    5. 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.
    6. Return the pointer to the TCB as the function's return value.

  7. Write the thread_cleanup C function:
    1. Remove the TCB from the front of the ready list.
    2. Free the stack for the last thread that called thread_cleanup.
    3. 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.
    4. Free the TCB that was removed from the front of the ready list.
    5. 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):

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 March 25. Be careful: one minute late is late.


Last modified on March 21, 2018.

Comments and questions should be directed to pjh@cs.unh.edu