Operating Systems--Spring 2005

    Home | | Schedule | | Assignments | | Lecture Notes

    Project 2: Processes

    First checkpoint due: Friday, Feb 18 (see below)
    Full Project Due date: Friday, Feb 25

    Part One: Learning to Fork/Wait/Exec

    In this project, you need to learn how to use the fork, wait, and exec commands. You should develop a C++ program, named process.cc. Let's call the parent process executed by the program Process A. Process A creates two child processes: Process B and Process C. Process B also creates two child processes: Process D and Process E. Each process should have an output announcing that it has started execution. Have the life of each of these processes be long enough (e.g. 30 sec) so that you can observe them while they are still executing. You can increase the lifetime of a process by using the sleep( ) function:

      sleep(int n);
      Invokes the UNIX sleep command, which causes the process to wait for n seconds.

    When each process wakes up from sleeping, it should terminate itself.

    Use the process program to answer the following questions:

    • a) Run the process program in the background (use &) and use the UNIX command

        ps -l

      to determine the ID of each process and it's parent (PID and PPID). Copy and paste the output of ps -l to a text editor and save it as process_ps.txt. (You will turn this in). Use the ID's to draw a diagram of the process tree that your program generates. Make sure to indicate the ID of each process on your diagram, and make the ID's and parent-child relationships consistent with the information in your process_ps.txt file.

    For the next questions, run your program in the background, and try to kill one process at a time to see what will happen. To kill a process, find its pid using the ps command. You can then kill it using the UNIX command:

      kill -9 PID

    (Read the manual page in Unix on process status, i.e., man ps, and learn how to interpret the meaning of each column in the output of the ps -l command. Also read the man page on kill.)

    • b). If a parent process is killed, what happens (if anything) to its child processes? Do they stay alive? If so, what happens to their PPID?
    • c). Suppose a parent is going to wait on a child via the wait command and the child is killed. That is, the parent has not yet executed the wait command. What happens (if anything) to the child process? What happens (if anything) to the parent process? (Note: You may have to insert an extra sleep( ) command in the parent to make sure you can kill the child before the parent waits).
    • d). If a child's sibling process is killed, what happens (if anything) to the child process?
    • e). Suppose a process executes another process via one of the exec commands (e.g., execv), does the PID of the process change? (Hint: You might want to exec a long running process, e.g. sleep. Use execlp( ) for this one).

    Be as precise as possible when discussing the answers to these four questions.

    CAUTION: Before you log out or try another test execution, always use ps to ensure that all the processes you have previously created are no longer executing.

    Note: You will need the following include files for process.cc:

      #include <stdlib.h>
      #include <unistd.h>
      #include <sys/wait.h>

    Turn in:

    • A printout of the files, process.cc and process_ps.txt
    • Submit the files process.cc and process_ps.txt using the submit function (see below).
    • A diagram of the processes generated by process.cc
    • Written answers to questions b - e.

    Part Two: Writing a Shell Program

    Suppose you work for a company that is in the process of creating the ULTIMATE Operating System (UOS). One goal of this OS is to provide different shells for the users, some of which will offer numerous functionality and others that will not. You are in charge of developing the tiny shell (tsh). In order to complete your task, you'll need to become familiar with input/output redirection, fork, exec, pipes, and environment variables. Your tsh needs to be rewritten in C++, and the source code should be placed in a file named tshell.cc.

    The basic ground rules for the development of your tsh is that your program cannot exec (any variant) the sh program. In other words, your tsh must be stand alone; it can not rely upon another shell to function, Thus, YOUR program (and not some other program) must manipulate the file descriptors, set up and break down the pipes, etc. Your boss for UOS wants to ensure your code can handle the following capabilities:

    1. Redirecting input: myprog < myinput
    2. Redirecting output: myprog > myoutput
    3. Appending redirected output: myprog >> myoutput
    4. A pipe between two commands: ls -l | grep root
    In addition, your boss for UOS wants your tsh to be implemented in the following manner:
    1. Use the execvp variant of exec.
    2. The prompt of tsh should be set to ``tsh.'' concatenated with the current working directory. For example:

        tsh./home/fac/croyden>

      The current value of the working directoryis obtained through getenv. For example:

        getenv("PWD")

      will return a pointer to a string containing the current working directory.

    As in most shells, the valid input to tsh will consist of, from left to right, the commands to be executed along with their parameters connected by pipe symbols, with any I/O redirection occurring on the far right of the line. I/O redirection can occur in either order. For example, either

    grep fork | wc -l < infile >> report
    or
    grep fork | wc -l >> report < infile

    should produce the same result. You should assume that any input file redirection is for the first command and any output file redirection is for the last command.

    You don't have to do any error checking. Error handling is an important part of any program that will be widely used; however, it adds substantially to the complexity of the program. Thus, your boss wants the first draft (i.e., what is submitted) of your tsh without any error handling. In other words, your tiny shell will only be tested with valid input.

    The commands listed above are only to illustrate how your tsh should function. While not needed to develop your tiny shell, you are welcome to read the manual pages on any of the above commands that are unfamiliar. I do suggest, however, that you check out the manual pages for the following commands: waitpid, dup, open, and close.

    The parser
    To help you with your program, you are provided with a Parser class, written by Nick Bauer at the Colorado School of Mines, that will take a command line and divide it up into its relevant components. The Parser class is contained in the files:

      parser.h
      parser.cc

    You may copy these files from the directory ~csci346/projects/project2. You should study the description of the Parser class in parser.h and examine the data available to you in this class. Briefly, the Parser class provides a method,

      ParseLine(char *commandLine)

    that takes a command line string and parses it into its component commands (up to 10, but you will only need 2) and any input or output redirection (including a boolean to indicate if the output should be appended or not to the output file), and the input and output file names (if any). It also has a flag that indicates whether the command line should be run in the background. Commands are stored in an array of structs (type: CommandLine). Each struct has the name of the command, a list of arguments for that command (args), and the number of arguments. Note that the command name is the first argument in the list, so args can be used like argv (very useful when using execvp). Finally, numCommands gives the total number of commands minus 1 (i.e. if there is 1 command in the line, numCommands is 0).

    Miscellaneous Notes

    • To receive a high grade on this programming assignment, you must submit a program that is correct and has good design and style.
    • In the notes for lecture 9, there is brief pseudocode on how a shell functions.
    • Redirection of file I/O and UNIX pipes were covered in lecture 11. Use your notes from lecture 11 and read the handout, "An Introduction to Concurrency in Unix-based C Through Annotated Examples", by Henry M. Walker. Lastly, please note that multiple program statements are need to do the task of redirect I/O and to establish pipes.

    Turning in your project:

    Checkpoint:
    • You are required to submit the code for part one of the project (process.cc), as well as a version of tshell.cc that executes single commands with arguments (but does not necessarily redirect input or output or deal with pipes) on Friday, February 18.
      • Submit the soft copy of your process.cc and tshell.cc files by typing:
        ~csci346/bin/submit csci346 project2check
      • Turn in a printout of your process.cc and tshell.cc files in class.
    • Turning in working programs by this date is worth 10% of your grade.
    • If you do not turn in process.cc and the simple version of tshell.cc (without I/O redirection or pipes) by February 18, then you will only be able to earn 90% of the total points on your complete project.

    Completed project:

    • Turn in your completed project (tshell.cc, process.cc, process_ps.txt and answers to questions) by Friday, February 25 in class.
      • Before class, submit the soft copies of tshell.cc, process.cc and process_ps.txt by typing:
        ~csci346/bin/submit csci346 project2
      • Turn in a printout of each of the process.cc, process_ps.txt and tshell.cc files.
      • Turn in your typed answers to the questions in part 1.
      • Turn in your diagram of the processes from part 1.


    Home | | Schedule | | Assignments | | Lecture Notes


    Constance Royden--croyden@mathcs.holycross.edu
    Computer Science 346--Operating Systems
    Date Created: January 9, 2004
    Last Modified: February 10, 2005
    Page Expires: January 8, 2006