Last Updated: 2021-02-14 Sun 10:10

CSCI 4061 HW04: Parent/Child Pipes and I/O Redirection

CODE DISTRIBUTION: hw04-code.zip

CHANGELOG: Empty

1 Rationale

Parents can often communicate with children through I/O operations, most often via pipes. Such communications are also possible via I/O redirection of standard output. These techniques are demonstrated in the provided HW code. Insight on how how pipelines of commands like cat file.txt | wc can be set up is present in the code examples.

I/O redirection is a powerful tool that allows output that would normally be printed to the screen or read from keyboard typing to come from other sources without the program needing to take any special actions. The basic system calls that facilitate this are the dup() and dup2() calls which manipulate a process file table. This lab demonstrates how these are used.

1.1 Associated Reading

  • Ch 3 of Stevens and Rago discusses basic I/O functions like read()/write() and the dup2() function for I/O redirection
    • 3.10 discusses specific aspects of file "sharing"; e.g. internal OS mechanisms for files that explain the behavior of open() followed by fork()
    • 3.12 Discusses how dup() and dup2() affect the internal OS structures for I/O
  • Ch 15.2-3 of Stevens and Rago discusses pipe basics such as the effects of the pipe() system call. It includes some useful diagrams to relate the intent of pipes

1.2 Grading Policy

Credit for this HW is earned by taking the associate Quiz which is linked under Gradescope. The quiz will ask similar questions as those that are present in the QUESTIONS.txt file and those that complete all answers in QUESTIONS.txt should have no trouble with the quiz.

See the full policy in the syllabus.

2 Codepack

The codepack for the HW contains the following files:

File State Description
QUESTIONS.txt Edit Answer questions in the file to complete the lab
parent_listen.c Edit Problem 1 file to analyze/edit
capture_stdout.c Edit Problem 2 file to analyze/edit

3 What to Understand

Make sure you get a good understanding of

  • how read()/write() work to manipulate information in file descriptors
  • how forked processed share open file descriptors
  • how dup2() can be used to redirect output from one file descriptor to another
  • the basics of getting a child which would normally print to the screen to print into a different source such as a pipe
  • How dup2() can be used to redirect output from one file descriptor to another

All of these things will show up in projects.

4 Questions

                           _________________

                            HW 04 QUESTIONS
                           _________________


- Name: (FILL THIS in)
- NetID: (THE kauf0095 IN kauf0095@umn.edu)

Write your answers to the questions below directly in this text file.
HW quiz questions will be related to the questions in this file.


PROBLEM 1 `parent_listen.c'
===========================

  `parent_listen.c' demonstrates setting up a parent to 'listen' to
  output that is `write()''n to a pipe. Examine its contents carefully
  as it demonstrates several new system calls including `pipe()' along
  with the common error reporting function `perror()'.  Comments give
  some indication of their use but some textbook or man-page reading
  will give additional detail.


A
~

  Compile and run the program in `parent_listen.c'. Show it's output
  below.


B
~

  Consider the call to `pipe()'. Do some research on Unix pipes to
  figure out what a pipe does and explain in a few sentences.


C
~

  Observe the calls to `read()' and `write()'. Their meaning should be
  self-evident (read and write data) but the parameters to these
  functions are interesting. Do some reading and explain the 3
  parameters to each of them. Also explain their return value.


D
~

  If you run the program a number of times, you may see output in
  different orders: the parent may report reading the data before the
  child has written it.  Data is `write()''n and `read()' from pipes
  much faster than it can be put onto the screen. This in combination
  with the unpredictable OS scheduler leads to output that can be a bit
  mixed up. (Note that the `usleep()' call is used to exacerbate these
  concurrency issues to make them occur more frequently; removing these
  calls will make the problem less frequent but will not eliminate it).

  Adjust the position of the wait() call to guarantee that the order
  that the messages are printed is always follows:
  1. Parent creating child process
  2. Child wrote 17 bytes
  3. Parent read 17 bytes
  4. Child said: 'Send $$$ please!'

  Paste your full code below.


PROBLEM 2 `capture_stdout.c'
============================

A
~

  Compile and run the program in `capture_stdout.c'. Show its output.


B
~

  The calls `dup()' and `dup2()' are used in this program to manipulate
  file descriptors. Explain the effects of the lines below. You may need
  to consult a programming manual to learn more about `dup()' and
  `dup2()'.
  ,----
  | int stdout_bak = dup(STDOUT_FILENO);
  | dup2(my_pipe[PWRITE], STDOUT_FILENO);
  | ...
  | dup2(stdout_bak, STDOUT_FILENO);
  `----


C
~

  The use of `printf()' normally puts output directly on the
  screen. Explain why the statement
  ,----
  | printf("%d In the pipe, five by five",
  |        getpid());           
  | 
  `----
  does not print to screen as usual.


D
~

  Modify the code so that the `In the pipe...' expression is printed by
  a child process.
  - Add a `fork()' AFTER `dup2()' redirects standard output but before
    the print
  - Add an `if()' to distinguish between parent and child
  - The child should print then exit
  - The parent should restore stdout then read from the pipe
  - Add a `wait()' to guarantee the parent waits for the child to
    complete prior to reading from the pipe
  Paste your completed code below.


NOTE on Large Child Output
~~~~~~~~~~~~~~~~~~~~~~~~~~

  The completed `capture_stdout.c' file should get a child to write into
  a pipe and the parent to read from that pipe. The parent reading is
  currently reading as the lines
  ,----
  |   char buf[2048];
  |   int bytes_read = read(my_pipe[PREAD], buf, 2048);
  `----
  assume that the child output will be no larger than 2048 bytes.  The
  next problem demonstrates a useful allocation pattern which can be
  used to handle large / unknown input sizes.

5 Again, What to Understand

Make sure you get a good understanding of

  • how read()/write() work to manipulate information in file descriptors
  • how forked processed share open file descriptors
  • how dup2() can be used to redirect output from one file descriptor to another
  • the basics of getting a child which would normally print to the screen to print into a different source such as a pipe
  • How dup2() can be used to redirect output from one file descriptor to another

All of these things will show up in projects.


Author: Chris Kauffman (kauffman@umn.edu)
Date: 2021-02-14 Sun 10:10