Assignment 11, due Apr. 13

Part of the homework for CS:3620, Spring 2018
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

On all assignments, your name must be legible as it appears on your University ID card! Assignments are due at the start of class on the day indicated (usually Friday). Exceptions will be by advance arrangement unless there is what lawyers call "an act of God" (something outside your control). Homework must be turned in on paper, either in class or in the teaching assistant's mailbox. Never push late work under someone's door!

  1. Background: Look up the Unix/Linux pipe() kernel call. Your goal in this exercise is to suggest how pipes are implemented inside the kernel. Recall that a user file descriptor returned to a user when you open a file or, in this case, create a pipe, is an integer index into an array of open-file objects that the kernel maintains on behalf of each process. The entries in this array are pointers to open-file data structures (objects). The class "open-file" has many subclasses, things like disk file, terminal and pipe are all, logically speaking, subclasses of open file.

    Also recall that when a process forks, the newly created process gets a copy of the parent's open file table. This means copies of the pointers in that table, not new objects. Both parent and child have all the same access rights to each file the parent had open, but if either process opens more files after the fork, those are not shared.

    a) The pipe() kernel call returns two file descriptors. Do these descriptors refer to the same object or different ones. If different, do the objects members of the same subclass of open file or different subclasses? If different, what is the difference? (0.3 points)

    b) Ultimately, the pipe is probably implemented with a bounded-buffer implementation of a FIFO queue. How is this related to the object or objects discussed in part a? (0.3 points)

    c) What other objects would you probably include as part of the implementation of the pipe? (Hint, pipes are only really useful if they are used for interprocess communication.) (0.4 points)

  2. Background: Look up the Unix/Linux pipe() kernel call again, and also the dup2 and fork() kernel calls. Recall that the file descriptors 0, 1 and 2 are used for standard input, standard output and standard error.

    Our goal here is to think about how these kernel calls are used by the Unix/Linux shells to implement shell pipes. In the standard shells, if you type commanda|commandb, where the two commands may have any number of command-line arguments, commanda is launched with its standard output directed into a pipe, and commandb is launched in parallel with its standard input taken from that pipe.

    a) Is the pipe created before or after the forking involved in launching the commands? Why? (0.3 points)

    b) How many fork operations must be involved. You know how the shell works to launch one command, this question asks how to launch two commands running in parallel. (0.3 points)

    c) Where does the call (where do the calls) to dup2() go in relation to the pipe(), fork() and execve() calls and what are their parameters? A complete answer will explain how the file descriptors returned by fork() end up becoming standard input and standard output for the launched commands. (0.4 points)

  3. Background: A final question among what may be too many questions about the pipe() system call. It is good practice for a program to dispose of any resources it does not need as soon as it learns that it no longer needs them. For file descriptors, the close() operation deletes the pointer (sets it to null) in the open file table of a process.

    a) Look at your answer to question 2 and indicate which file descriptors should be closed when and where in the code between the time pipe() is called and the two execve() calls that complete the launching of commanda and commandb. (0.5 points)

    b) Look at your answer to part a and to question 1 and suggest a way that the kernel can know when to deallocate the objects associated with a file descriptor. Some call to close() will do this, but which one and how can the system track when to actually delete the object? (0.5 points)