Last Updated: 2021-02-08 Mon 09:17

CSCI 4061 HW03: Waiting without Waiting

CODE DISTRIBUTION: hw03-code.zip

  • Download the code distribution every HW
  • See further setup instructions below

CHANGELOG:

Mon Feb 8 09:16:46 AM CST 2021
The missing C files have been added into hw03-code.zip and can be obtained by re-downloading the codepack.

1 Rationale

After creating child processes with the fork() call, a parent is obliged to wait for them at some point but the waitpid() provides capabilities such as non-blocking (non-hanging) waits illustrated in this HW. This gives insight into how background shell commands like ./program & may be implemented.

Use of the read() system call to accumulate input can be tricky. This lab also analyzes a simple program that demonstrates a common pattern useful to append all input to a single area of memory.

1.1 Associated Reading

Stevens/Rago

  • Ch 8.6 of Stevens and Rago also discusses wait()/waitpid() but does not cover the WNOHANG option in much detail
  • Ch 3 of Stevens and Rago discusses basic I/O functions like read()/write()

OR Robbins/Robbins

  • Ch 3.4 of Robbins & Robbins discusses waitpid() and the WNOHANG option
  • Ch 4 of Robbins & Robbins discusses basic I/O functions read()/write()

Consult C documentation for information on the malloc(), free() and realloc() functions to understand their use.

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 HW
wait_loop.c Edit Problem 1 file to analyze/edit
parent_listen.c Edit Problem 2 file to analyze/edit

3 What to Understand

Make sure you get a good understanding of the following.

  • Basic string processing of input lines with fgets() and strncmp()
  • Use waitpid() blocking or non-blocking waits and how its return values indicate whether a child has finished or not
  • Retrieval the exit code of a child using macros
  • How read()/write() work to manipulate information in file descriptors
  • How data can be read and accumulated in program memory

All of these things will show up in projects.

4 Questions

                           _________________

                            HW 03 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 `wait_loop.c'
=======================

  Examine the C file `wait_loop.c'. It implements a primitive
  interactive loop asking a user to type things while a child process
  runs in the background. By default, the provided `sleep_print.c'
  program is used which creates a delay before the program
  finishes. Make sure to compile `sleep_print' then compile
  `wait_loop.c' and experiment with its behavior.

  Here is a brief demo.
  ,----
  | > gcc -o sleep_print sleep_print.c 
  | > gcc wait_loop.c
  | > ./a.out
  | Type text then press enter to check on child:
  | >> hello there
  | Entered text: 'hello there'
  | Waiting
  | CHILD: Awake and Done 
  | CHILD FINISHED: 
  | 
  | Type text then press enter to check on child:
  | >> what?
  | Entered text: 'what?'
  | Waiting
  | Child not finished: wait returned -1
  | 
  | Type text then press enter to check on child:
  | >> stop
  | Entered text: 'stop'
  | Waiting
  | Child not finished: wait returned -1
  | 
  | Type text then press enter to check on child:
  | >>  Ctrl-c
  | > 
  `----


A
~

  Alter the code so that when the child has completed execution, the
  program breaks out of the loop and the program ends normally. Paste in
  the code you used for this.


B
~

  Adjust the code so that the exit status of the child process is
  printed when it finishes. Make sure to use the macros
  `WIFEXITED(status)' and `WEXITSTATUS(status)' to deal with the
  `status' set by `waitpid()'.  Paste the code you added for your
  answer.


C
~

  Make changes so that if the user types in the string `quit', the
  program exits immediately without waiting further for the
  child. Example:
  ,----
  | > a.out
  | Type text then press enter to check on child:
  | >> quit
  | Entered text: 'quit'
  | Quitting
  | Exiting wait_loop
  | > CHILD: Awake and Done 
  `----
  Note that the child eventually prints output to the screen which is
  fine.

  You will need to check the user input using either the `strcmp()'
  (unsafe) or `strncmp()' (safer) function. Do some research on this
  function if it is unfamiliar as it will prove generally useful.

  Paste the code you used below.


D
~

  The current call to `waitpid()' blocks, pausing execution of the
  parent process until the child finishes. Look up the option to pass to
  `waitpid()' that will allow it to do a non-blocking wait which returns
  immediately if the child is not finished. A sample behavior is below.
  ,----
  | > a.out
  | Type text then press enter to check on child:
  | >> stuff
  | Entered text: 'stuff'
  | Waiting
  | Child not finished: wait returned 0
  | 
  | Type text then press enter to check on child:
  | >> more stuff
  | Entered text: 'more stuff'
  | Waiting
  | Child not finished: wait returned 0
  | 
  | Type text then press enter to check on child:
  | >> CHILD: Awake and Done 
  | Looks like you're finally up
  | Entered text: 'Looks like you're finally up'
  | Waiting
  | CHILD FINISHED: Exit status 5
  | Exiting wait_loop
  | > 
  `----

  Paste your entire code for `wait_loop.c' below.


PROBLEM 2 `append_all.c'
========================

  Examine the code in `append_all.c' which makes use of the `read()' and
  `write()' I/O system calls in an interesting pattern.


A
~

  Compile and run the program and experiment with entering data into it
  and pressing 'Enter'. Start with simple single letter inputs and then
  extend you inputs to longer strings.  Show your session and explain
  why read() always seems to read one more character than you type.


B
~

  Describe the initialize size of the array `input' in `append_all.c'
  and how it changes over the run of the program.
  - What standard C function is used to initially allocate memory for
    `input'? How does it work and how much space does `input' initially
    occupy?
  - what C function is used to alter its size? How does it work?


C
~

  Restart the `append_all.c' program and type the specific input below
  in at the prompts. Show the output produced and describe *exactly how
  many read() calls* result from entering this input. This should
  solidify your understanding of the main loop in the program.

  ,----
  | > 123456
  `----


D
~

  In append_all.c, the read call is followed by a commented line:
  ,----
  |     int nread = read(STDIN_FILENO, input+cur_pos, max_read); // perform read()
  |  // int nread = read(STDIN_FILENO, input, max_read);         // this read() call would be an error: why?
  `----
  This commented line contains a common error for those new to `read()'
  system call or input accumulation in general.

  Comment the current read() call and uncomment the line marked as an
  error so that the code reads:
  ,----
  |  // int nread = read(STDIN_FILENO, input+cur_pos, max_read); // perform read()
  |  int nread = read(STDIN_FILENO, input, max_read);            // this read() call would be an error: why?
  `----

  Recompile the program and run it entering various inputs. Describe why
  this line is error and relate it to what the program now erroneously
  produces for output.

5 Again, What to Understand

Make sure you get a good understanding of the following.

  • Basic string processing of input lines with fgets() and strncmp()
  • Use waitpid() blocking or non-blocking waits and how its return values indicate whether a child has finished or not
  • Retrieval the exit code of a child using macros
  • How read()/write() work to manipulate information in file descriptors
  • How data can be read and accumulated in program memory

All of these things will show up in projects.


Author: Chris Kauffman (kauffman@umn.edu)
Date: 2021-02-08 Mon 09:17