Name / ID (please PRINT) Sequence #: Seat Number: CS 3733.001 -- Operating system Summer 2017 -- Final -- August 12, 2017 @10:00am You have 120 min. Good Luck! This is a closed book/note examination. But You can use the reference card(s) given to you. This exam has 10 questions in 13 pages. Please read each question carefully and answer all the questions, which have 100 points in total + bonuses. Feel free to ask questions if you have any doubts about problems. Partial credit will be given, so do not leave questions blank. BONUSES: First five questions will be used to assess how well all students learn the selected key concepts covered in this course. So, please take time to answer all of the first five questions so we can better assess the course. To further encourage you, we offer bonus credit, which will be the 10% of the total grade that you will get for the first five questions. So if you answer all of them (50 points) correctly, you can earn up to 5pt bonus credits. This is in addition to the 3pt bonus that I had offered for an in-class exercise during the semester. You can also earn 2pt bonus credit, if you complete the boldfaced two columns of the following table. Please do this after answering all the questions in the exam and complete both columns. Question 1 2 Topic Review Questions (all from tk01 to tk06) Review Questions (all from tk07 to tk12) Possib le Points Difficulty level of this question 1: Easiest 10: Most difficulty Student Expects to receive out of 10 /10 10 /10 3 Memory Mng. (tk07-) 10 /10 Student Received 4 Threads-I (tk09-) 10 /10 5 Synchronization-I (tk10-) 10 /10 6 Virtual Memory - Demand Paging (tk08-) 10 /10 7 Threads-II (tk09-) 10 /10 8 Synchronization-II (tk10-) 10 /10 9 Signals (tk11-) 10 /10 10 Communications -socket prog., (tk12-) Bonus 2pt If this table is completed 2 Bonus 4pt For the in-class exercises 4 Bonus 5pt 10% of first 5 questions 5 Total 111 10 /10 1
1. [10 points] Answer the following questions from the first half of the course with short explanations. You can also draw figures to better explain your reasoning if needed. a. [2pt] Explain the differences between System calls and Library function calls in C? b. [2pt] Draw a state diagram to show how the state (new, ready...) of a process changes? 2
c. [2pt] List at least two of the performance metrics used to compare scheduling algorithms. d. [2pt] If a system call (e.g., read()) returns -1 and error is set to EINTER, how should we interpret this and handle it?. e. [2pt] What is a pipe? How can we create one in Linux/Unix?. 3
2. [10 points] Answer the following questions from the second half of the course with short explanations. You can also draw figures to better explain your reasoning if needed. a. [2pt] What is a translation look-aside buffer (TLB) and how is it used in a paging system? b. [2pt] What are the goals and benefits of using virtual memory? (List at least two) 4
c. [2pt] Suppose you are given a function void *myfunc(void *argv); Draw the diagrams to show the difference in flow of executions when (i) it is called like a regular function (e.g., myfunction(&id);) in main, and (ii) it is used in pthread_create(&tid, NULL, myfunc, &id); in main d. [2pt] What is critical section (CS) and why does it need to be executed atomically? e. [2pt] Complete blanks in the following sentences about signals by using the appropriate keywords from the following list: generated, delivered, lifetime, pending, catch, signal handler, ignore, mask, block, unblock, default action. A signal is A signal is when the event that causes the signal occurs. when the process takes action based on the signal. A signal that has been generated but not yet delivered is. 5
3. [10 points] Memory Management a. [4 points] Suppose that the virtual address space is 8 Mbytes, the physical memory is 256 Kbytes, and the page/frame size is 4 Kbytes. Show how to determine the following bits: i. [0.5pt] Number of bits for virtual address = ii. [0.5pt] Number of bits for physical address = iii. [1pt] Number of bits for offset (d) = iv. [1pt] Number of bits for page number (p) = v. [1pt] Number of bits for frame number (f) = b. [4 points] Suppose we use TLB in the above system with the following page table and TLB table entries. For memory address translation, suppose the TLB access time is 8 ns and the memory access time is 30 ns. initial page table Index Valid Frame 0 1 6 1 1 5 2 1 4 3 1 2 4 1 3 TLB For the logical/virtual address given in binary below, find the corresponding page number and frame number while also estimating the time to access the actual data/instruction in the physical memory (suppose we always first check TLB and then check page table if the page number is not in TLB). Also give the corresponding physical address. The given logical/virtual address is 000 0000 0100 1101 0011 1110 [1pt] Page # [1pt] Access time [1pt] Frame # [1pt] Physical Address = = = = c. [2 points] Suppose you are writing a C program to translate a given logical/virtual address (LA) to a physical address (PA) in the above system. You need to first find the page number (p) and offset number (d). Then get frame number (f) from page table and determine PA. For the above system in 3.a, what statements would you use to find p, d and PA? Suppose LA is given. unsigned int p,d,f,pa,la=0x1f28a3; // 001 1111 0010 1000 1010 0011 d = p = f = page_table[p]; PA = page Frame 2 7 3 4 1 5 6 9 6
4. [10 points] Threads - I Suppose we want to pass one double value and one integer value as parameters to a thread called testthread(). For this, we need to declare a structure containing double and integer variables as shown below. You are asked to complete the following program to pass 5 and 3.14 as parameters to testthread(), which then simply prints the received parameters. You can ignore error checking. Assume all the necessary libraries are included. struct param { int i; double d; void *testthread(void *args) { void main() { pthread_t tid; int i1=5; double d1= 3.14; pthread_create(&tid, NULL, testthread, ); pthread_join(tid, NULL); 7
5. [10 points] Synchronization - I Suppose there are three threads P, Q and R. Each has some sequential code sections represented as function calls and then each thread updates a shared variable count, as shown in the below table. Define and initialize semaphores and then solve the coordination and the critical section problems by using acquire/release or sem_wait/sem_post such that QS1() is executed after PS1()and RS1(), PS2() and RS2() are executed after QS2() /* Semaphores and initial Values: */ 1pt P Q R PS1(); QS1(); RS1(); 6pt PS2(); QS2(); RS2(); count = count + 3 count = count - 2 y = count + 5 3pt 8
6. [10 points] Virtual Memory Page replacement: consider a demand paged virtual memory system with 4 frames allocated to a process. Assume that initially no frames are allocated to any pages and the process will make the following sequence of page references: 1 3 2 4 2 5 1 3 2 4 2 5 3 1 For each of the following page replacement algorithms, indicate which pages are in memory after each reference and determine which references produce page faults. Circle the page faults. For each algorithm, also give the total number of page faults. a) [3pt] FIFO, number of page faults = Page reference 1 3 2 4 2 5 1 3 2 4 2 5 3 1 b) [4pt] LRU, number of page faults = Page reference 1 3 2 4 2 5 1 3 2 4 2 5 3 1 c) [3pt] Optimal, number of page faults = Page reference 1 3 2 4 2 5 1 3 2 4 2 5 3 1 9
7. [10 points] Threads- II Suppose we have the following thread to return an integer value to the parent thread. void *return_long_thread(void *arg) { long n1=0; static long n2=0; long *p1; /* some work is done and the same value is saved into both n1 and n2 */ p1 = (long *) malloc(sizeof(long)); if (p1==null) exit(); *p1 = n1; return(/* something */); a) [2pt] Suppose we use return((void *) &n1); This would compile and work. But the parent thread may not be able see the same correct result when executed at different times. Explain what is the problem in using this return statement in the above thread implementation. b) [3pt] How about using return((void *) &n2 ); or return((void *) p1 ); Actually both work when we have only one instance of the thread! Explain why they work. c) [3pt] Identify and explain which return statement in part (b) may not work when we have multiple instances of the above thread. d) [2pt] Fill the blanks so the parent thread can get the return value and print it. long *p; pthread_join(&tid, ); printf("returned integer is %ld\n", ); 10
8. [10 points] Synchronization - II Suppose a novice has implemented the following program having three threads P, C_odd, and C_even. Each thread has some sequential code sections represented as function calls while also having a critical section. Thread P produces an item and inserts it in into a shared queue Q, which is not bounded (e.g, a linked list is used so we can always insert an item) and increases count by 1. Threads C_odd gets an item from the list when count is greater than zero and odd while C_even gets an item when count is greater than zero and even. Suppose all linked list functions Insert() and GetItem() work fine. However, the below program does not work correctly! The novice often sees different outputs or significant CPU usage without any output. You are asked to solve the problems of race condition and busy waiting in this implementation. int count=0; while(1){ Pa(); List *Q=Init(); P C_odd C_even Insert(Q,item); count++; Pb(); while(1){ C1a();// print count while(count<=0 count%2==0); itemodd = GetItem(Q); count--; C1b(); while(1){ C2a();// print count while(count<=0 count%2==1); itemev = GetItem(Q); count--; C2b(); Give your new solution in the below table. You can use the same linked list functions etc, as above. int count=0; List *Q=Init(); P C_odd C_even while(1){ while(1){ while(1){ Pa(); C1a();// print count C2a();// print count Pb(); C1b(); C2b(); 11
9. [10 points] Signals Our program calls two functions important_task(); and usual_task(); in an infinite loop. You are asked to complete the below program to implement the following two features: (i) The program should NOT quit when user presses ctrl-c which generates SIGINT. Instead, it handles it using the the my_sig_handler(); function, which is implemented below. (ii) The execution of important_task(); should not be interrupted by any signal. So block all the signals before calling it. After calling it, you need to restore the previous old mask. For a clear code, ignore error checking for now! // all the necessary libraries are included and // the following functions are already implemented, just use them important_task() { /* do something important /* usual_task() { /* do something /* void my_sig_handler(int signo){ fprintf(stderr, "Ctrl-c is pressed, but I will not quit!\n"); void main(){ struct sigaction act; sigset_t allsig, oldsig; while(1) { important_task(); usual_task(); 12
10. [10 points] Communications - Implement a simple client-server program using TCP sockets. The server always waits for connection requests on a welcome socket in an infinite loop. Upon receiving a connection request, the server creates a connection socket and sends a randomly generated integer (e.g., num=rand();) to the client. The client will first establish a TCP connection with the server. It then waits to receive a number from the server. Upon receiving the number, the client sends the same number back to the server and then sends a text message (e.g., "Hello") to the server. The client then closes the connection and quits. The server gets the number and a message from the client. If it is the same number that it sent before, then the server prints the received message else prints "no match". Then it closes that connection. The server will continue to wait for another client request on welcome socket. When implementing client and server programs below, please focus on the key system calls and in which order to call them while using generic parameters (e.g., IPaddress, portnum) rather than actual structures. Also ignore error checking and assume all the necessary libraries are included. /* server.c */ int serverip = 1.1.1.1; // generic int serverport = 2017; void main(){ int ws, cs; /* welcomesocket, connsocket */ int num1; char buff[10]; /* client.c */ int serverip = 1.1.1.1; // generic int serverport = 2017; void main() { int cs; /* clientsocket*/ int num1=; char *msg="hello"; 13