Try Firefox!

Lab 9: Pipes


Overview
The program you will write for this lab will allow the user to enter an arbitrary mathematical function in one variable. Here are examples of some functions in one variable:
    2x        sin(x)2      1 - ex     2x2 + 3x + cos(ex)
Furthermore, the user will enter an arbitrary domain [a,b] for x, and an arbitrary number n of evaluation points in that domain. Finally, your program will compute the average value of the function evaluated at n evenly spaced points from a to b. Here's an example problem your program would solve:
Compute the average value of f(x) = 2x, evaluated at 8 points evenly spaced from 0 to 4.
Arbitrary function? Arbitrary domain? Arbitrary number of evaluation points? This sounds like a lot of capability to have to program for, but we're going to take advantage of pipes to offload nearly ALL of the work to a child process.

Here's what a correct solution looks like when executed.

bash$ fna       ← Program "fna"  (function average)
2*x             ← The function to be evaluated
0 4 8           ← Domain is [0 4], 8 evaluation points
4.000000        ← Answer
x^2+5*x-10      ← Another function
1 8 8           ← Domain is [1 8], 8 evaluation points
38.000000       ← Answer
s(x)            ← Another function: sine(x)
0 3.14 30       ← Domain is [0 pi], 30 evaluation points
0.615136        ← Answer
^D              ← ^D terminates your program
	
fna assumes input is in the following form: f(x) lo hi npts, where The output of fna is the average of the function, evaluated at the indicated number of points, in the given range. Note: there is no other output, e.g., there is no text embellishment! fna will continue to run until terminated using ^D.

The UNIX utility we'll use to do most of the work is named bc: it will take care of parsing and evaluating arithmetic expressions. Here's how it would be used to calculate the value of the function y = x2 at x = 3 :

	
bash$ bc -l
x=3
x^2
9
	
Note how it works: you give a value for x and an expression in x to evaluate, and bc gives you the answer. Note also that we run bc using its -l option. This allows us to use these functions (see man bc):
    s(x):  sine
    c(x):  cosine
    e(x):  exponential, i.e. ex
    l(x):  natural log, i.e. ln(x)
	
For example:
	
bash$ bc -l
x=3.14159/2
c(x)
.99999999999911980765
	
How can we use bc to do what we want? Suppose your program sends to bc (through a pipe) an expression in x and some values for x. It then lets bc do the stuff its designed to do, getting answers back though another pipe. In this way your program offloads the hard part of calculating the value of an expression to another program that already knows how to do such things!

Part 0 (20 points)
Create a file ans.txt. Copy and paste the questions below into ans.txt, and add your answers. Review the Class 13 notes for info related to pipes.
1. What are the two reasons the system call "pipe" might fail?  Hint: RTFMP!


2. Consider the following chunk of code:
 
   int p[2];
   pipe(p);

   At any point after these two lines, why would the call 
   write(p[0],"Hello!",6) be invalid?


3. Consider the following chunk of code:
 
   int p[2];
   pipe(p);

   At any point after these two lines, why would the call 
   fdopen(p[0],"w") be invalid?

3. Consider the following chunk of code:
 
   int p[2];
   pipe(p);
   int i = fork();

   A read from p[0] will result in EOF (the end of file character)
   only if all file descriptors referencing the write end of the pipe
   (i.e. p[1]) have been closed.  After the above chunk of code, how
   many file descriptors reference the write end of the pipe?  Explain
   your answer!


	
Part 1 (50 points)
Do NOT do Part 2 until you have correctly completed this part! Write a program named fna in a C source code file named fna.c. fna.c should create a pipe then fork. The parent will write to the pipe what the child needs so it can compute function values. Note that the child will have exec'd bc to do this computation. In Part 1 the child only needs to write results to stdout. You do NOT have to deal with incorrectly formatted expressions (and note that valid expressions cannot contain any spaces). Here's an example:
	
bash$ fna
x^2
1 3 5
1.00000000000000000000
2.25000000000000000000
4.00000000000000000000
6.25000000000000000000
9.00000000000000000000
	
Some or all of the following functions / system calls may be useful:
pipe, close, fdopen, setbuf, fflush, dup2, fork, exec
	
Remember that, if you use C I/O, you need to concern yourself with buffering modes (or at least remember to call fflush to "flush the buffer". In particular, FILE* objects referring to pipes will be fully-buffered by default. Also, remember to man fdopen ... you'll really want that one! It will allow you to use fprintf and fscanf on pipes!

Part 2 (30 points)
This requires a working Part 1!
Establish two-way communication between parent and child by creating two pipes before forking. Have the parent send the values of x to the child over the first pipe, have the child calculate the value of the function then send it back to the parent over the second pipe. A correct Part 2 should wåork like the example given in the "Overview" section above.

You may find this diagram & algorithm helpful.

Submission instructions
Submit your lab09 directory. Include at least ans.txt, and fna.c, as well as a file README, which must contain your name and alpha, as well as an indication as to whether you are submitting a Part 1 or Part 2 version of fna.c. The submitted program must actually work! So if part 2 doesn't work, you must submit part 1 instead.


Christopher W Brown
Last modified: Thu Mar 12 13:57:05 EDT 2009