Homework 2
W4118 Fall 2001
DUE: 10/7/2001 at 11:59pm EST

W4118 Fall 2001 - Homework 2


Individual written problems are to be done individually. Group programming problems are to be done in your assigned programming groups. The deadline for group programming problems applies to both CVN and non-CVN students. All homework submissions are to be made via the submit programs. Refer to the homework policy page on the class web site for further details.

Individual Written Problems:

Exercise numbers refer to the course textbook, Applied Operating System Concepts. Each problem is worth 5 points.

  1. Exercise 3.1

  2. Exercise 3.7

  3. On all current computers, at least part of the interrupt handlers are written in assembly language. Why?

  4. Describe what happens in the Linux kernel when a timer interrupt occurs. Be sure to list the procedures that are called and explain the function of each.

  5. Describe what happens in the Linux kernel when a fork system call occurs. Be sure to list the procedures that are called and explain the function of each.

  6. Read the Linux source code and construct a state diagram to represent the relevant states that a process may be in at any given time. For each state, give the exact name used for the state in the source code.

  7. Exercise 4.1

  8. Exercise 4.4

Please complete and submit a private group programming assignment evaluation. The evaluation should be in a separate file called evaluation.txt that is submitted with your individual written assignment submission.

Group Programming Problems:

Programming problems are to be done in your assigned groups using the VM that has been assigned to your group. For all programming problems you will be required to submit source code, a README file documenting your files and code, and a test run of your programs. In addition, you should submit a cover sheet using either homework_work.txt or homework_nonwork.txt, depending on whether or not the programming assignment is completely working or not. For source code submissions, you only need to submit new source code files that you created and kernel source code files that you changed. You should clearly indicate your names, email addresses, and assigned group number on your submission. Each group is required to submit one writeup for the programming assignment.

You will build your own Linux kernel for this class. For each homework assignment, you will build a new Linux kernel. The image of the kernel you build for this assignment should be vmlinuz.hmwk2. Grading for this assignment will be done based on vmlinuz.hmwk2. Note that the version of Linux running as the Host OS on the CLIC machines is different from that of the Guest OS that you will modify running in VMware.

  1. (5 pts.) Compile and install your own Linux kernel on your VM. The Linux Kernel HOWTO describes how to do this in some detail. Note that there are several issues that we must address:

  2. (8 pts) Install the KDB kernel debugger from ftp://oss.sgi.com/projects/kdb/download/ix86/old/kdb-v1.8-2.4.2.gz. Note again that you will have to ftp this code from your host computer to your guest VM. Move the patch into /usr/src/linux and apply it with the following commands:
    1. cd /usr/src/linux
    2. gunzip kdb-v1.8-2.4.2.gz
    3. patch -p1 < kdb-v1.8-2.4.2 > /tmp/patchres
    Then look at the file /tmp/patchres. There should be one small error in there. Ignore this. If you have several errors (and are sure you're using the correct kernel and patch versions) let the TA staff know immediately. Otherwise, recompile the kernel with the patch.

    After you have patched the kernel, the Documentation/ subdirectory will contain man pages on kdb. Read them to familiarize yourself with its operation. You can also read a summary of kernel debugging techniques (which include kdb) at: http://www.xml.com/ldd/chapter/book/ch04.html. At any time you may press the pause button to enter the debugger and, once in the the debugger, type go to exit to the ordinary command prompt. Though we won't require you to use the debugger for this assignment, we will be testing to make sure it is installed!

  3. (30 pts.) The Linux kernel maintains state for each process as it executes. A process is identified by a process id number called a PID. Write a new system call in Linux that takes a PID as an argument, and returns the process state information for that process. Note that you will be adding this system call to the kernel based on the 2.4.2 kernel you previously built with kernel debugging installed.

    The prototype for your system call will be:

    	int pinfo(pid_t pid, struct pinfo *info);
    
    pid_t is defined in /usr/include/sys/types.h. You should define struct pinfo as

    struct pinfo {
    	int pid;			/* process id */
    	long state;			/* current state of process */
    	long priority;			/* process priority */
    	int parent_pid;			/* process id of parent */
    	int youngest_child_pid;		/* pid of youngest child */
    	int younger_sibling_pid;	/* pid of younger sibling */
    	int older_sibling_pid;		/* pid of older sibling */
    	unsigned long start_time; 	/* process start time */
    	long user_time;			/* CPU time spent in user mode */
    	long sys_time;			/* CPU time spent in system mode */
    	long cutime;			/* total user time of children */
    	long cstime;			/* total system time of children */
    	long uid;			/* user id of process owner */
    	char comm[16];			/* name of program executed */
    };
    

    in /usr/src/linux/include/linux/pinfo.h as part of your solution.

    Your system call should return 0 if it is able to locate the process information for the target pid. At a minimum, your system call should detect the following conditions and respond as described:

    The referenced error codes are defined as ESRCH and EINVAL, respectively, in /usr/src/linux/asm/errno.h

    You should start by reviewing the "How System Calls Work in Linux/i86" section of the Linux Kernel Hacker's (LKH) Guide. Note that because the Linux kernel changes over time, the procedure is no longer exactly correct. However, there are messages appended at the end of the section that will help significantly. Two more recent articles that discuss how to add system calls can be found here and here.

    You will also want to review Chapter 3 on "Processes" in the class linux reference book, Understanding the Linux Kernel.

    As explained in the LKH guide, each system call must be assigned a number. Your system call should be assigned number 222.

    Big Hint: Linux maintains a list of all processes in a doubly linked list. Each entry in this list is a task_struct structure, which is defined in /usr/src/linux/include/linux/sched.h. In /usr/src/linux/include/asm/current.h, current is defined to inline a function which returns the address of the task_struct of the currently running process. All of the information to be returned in the pinfo structure can be determined by starting with current.

    Bigger Hint: In order to learn about system calls, you may also find it helpful to search the Linux kernel for other system calls and see how they are defined. The file kernel/sched.c might give some useful examples of this. The getpid and getuid system calls might be useful starting points. The system call sys_getpid defined in /usr/src/linux/kernel/sched.c uses current and provides a good reference point for defining your system call.

    FINAL NOTE: Your kernel has partially reserved a slot in the syscall table for ni_syscall (when you see it, you will know what we are talking about). Since ni_syscall means "not implemented", do not be afraid to commandeer that slot.

  4. (17 pts.) To test your system call, write a C program that takes a PID as an argument and finds all the ancestors of that process. Your program should print the process state information for the specified process and for each of the ancestors of the specified PID. The information for the process and its ancestors should be printed in generational order, starting with the oldest ancestor.

    NOTE: Although system calls are generally accessed through a library (libc), your test program should access your system call directly. This is accomplished by utilizing the appropriate _syscall macro in /usr/include/asm/unistd.h. As explained in LKH, which _syscall macro you use is determined by the number of arguments passed to your system call.

    The output of the program should be easy to read, and the program should check for errors such as invalid input or too many/few arguments, and invalid PID. The ps command will provide valuable help in verifying the accuracy of information printed by your program. You can access detailed information on the ps command by entering man ps.

    Your writeup should include the program output from the following two testcases:

    Additional Information: