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, ¤t_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, ¤t_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
© Copyright 2024