1. Overview 2. Instructions

CS 460 – Programming Assignment 1
Implement Context Switching for Threads
(Due midnight Friday 2/6/2015)
1. Overview
In this programming assignment, you will implement a data structure and routines in both
C and x84-64 assembly to start a thread as well as switch between threads.
In order to do this, you must understand clearly
• How system stack and thread activation stack work
o Review lecture slides (set 3:14-29)
• Some key x86-84 general purpose registers and assembly routines
o Review lecture slides (set 3: 15, 30, 31)
• What happens during a thread context switch
o Review lecture slides (set 3: 14-29)
Context switching will take place by explicitly modifying the system stack pointer
register (%rsp on x86-64 machines) using an assembly routine.
The assignment must be done on lab machines (lx.encs.vancouver.wsu.edu) using your
encs login account. This assignment can be done individually or with a team of two.
Make sure you can visualize exactly what happens for each step before coding. You will
need to write in total only about 40 lines of code but it’s important to get them right.
Example binaries are also included so you know what the output programs should be.
2. Instructions
Login to lx.encs.vancouver.wsu.edu and copy
/encs_share/cs/class/cs460/proj1 to your home directory. The directory
includes
• Makefile
• Thread_test.c : you must implement your C test code (main) in this file
• Thread_start.s : you must implement thread_start routine in this file
• Thread_switch.s : you must implement thread_switch routine in this file
• Example_binaries: includes example programs for step 2.4 and 2.5.
The following data structure (and some other things) has been defined in thread_test.c.
typedef struct
{
void* stack_pointer;
void (*initial_function) (void);
}thread_t;
2.1.Write an assembly routine to start a new thread, with the prototype:
void thread_start(struct thread_t * old, struct thread_t * new);
This routine should do the following:
• Push all callee-save registers (%rbx, %rbp, %r12-15) onto the current stack.
• Save the current stack pointer (%rsp) in old's thread table entry.
• Load the stack pointer from new's thread table entry into %rsp.
• Jump to the initial function of new.
For some tips on writing assembly, check the references at the end of this document.
2.2.Write an assembly routine to switch between two threads, with the prototype:
void thread_switch(struct thread_t * old, struct thread_t * new);
This routine is similar to thread_start, and should do the following:
• Push all callee-save registers onto the current stack.
• Save the current stack pointer in old's thread table entry.
• Load the stack pointer from new's thread table entry.
• Pop all callee-save registers from the new stack.
• Return.
2.3.Complete thead_test.c to test your code:
The followings have been implemented for you
//create 2 global threads
thread_t current_thread;
thread_t stored_thread;
o Q1: Where do current_thread and stored_thread reside in memory?
//yield function, switching between current_thread and stored_thread
void yield(){
thread_t temp = current_thread;
current_thread = stored_thread;
stored_thread = temp;
thread_switch(&stored_thread, &current_thread);
}
//performYield function
void performYield(){
//continuously run the following
while (1){
printf("%s\n", "current_thread: perform yield");
yield();
}
}
You will need to implement the followings in main:
• malloc a suitable region for current_thread's stack. Experiment
with different stack sizes. Remember, stacks grow down, so the
initial value of the stack pointer should be set to the END of the
allocated range.
• current_thread is soon to start with performYield function, set
this function to be the initial function of current_thread.
• Given the above, stored_thread represents the main thread, soon
to be suspended and stashed.
o Q2: stored_thread’s stack does not have to be allocated.
Why not?
• call thread_start(&stored_thread, &current_thread).
•
After thread_start, have main continuously print a message
("stored_thread: perform yield") and call yield().
2.4. Compile and test your code
• Q3: Run your program with current_thread’s stack size from 128, 256, 512,
1024, 2048 Bytes. What do you expect for the outputs? What are the actual
outputs and explain why?
2.5. Stress test your code
Instead of having main and the performYield functions call yield() in an infinite loop,
have them do so for a fixed number of iterations.
• Notice that if main finishes first, the other thread's function will not get to
finish.
o Q4*: Why is this?
• Notice that if the other thread's function finishes first, the program will crash
with a Segementation Fault.
o Q5**: Why is this?
2. Submission guidelines and grading criteria
a. Submission
Please provide sufficient comments for your code. Clearly indicate if a step is incomplete.
Please zip all files
• A report file that includes test results and answers to Q1-Q5,
• The code, and
• A README file that describes how to run your code.
Submit the zip file on prog1 dropbox on Angel (Those having difficulties accessing Angel can
send the file to the TA’s email address: [email protected])
The code is expected to run on the lab machines (lx.encs.vancouver.wsu.edu).
b. Grading criteria
Criteria
Step 1 & 2
Step 3 & 4
Step 5
Points (/100)
40
40
20
3. References
a. X86-64 instructions
http://www.classes.cs.uchicago.edu/archive/2009/spring/226201/docs/handout-03.pdf
b. Function pointer syntax, http://www.cprogramming.com/tutorial/functionpointers.html