In the previous assignment you used children of the main process to do concurrent executions in a make utility. In this assignment we will do the same thing but the children will have a different program as their parent.
In the first part of the assignment you will write an independent program called pipecompiler that will take the name of two pipes as its command line arguments, read lines from one pipe, execute the corresponding command, and send a response back on the second pipe.
In the second part of the assignment you will modify your mymake program from Assignment 3 so that it sends all requests for execution to a single copy of pipecompiler which we assume is already running.
In the third part of the assignment you will use multiple copies of pipecompiler, spreading the load as evenly as possible. Note that this does not gain much in efficiency since all of the pipecompiler programs are running on the same machine. In the next (and last) assignment, you will replace the pipes with network communication and the compilers will be running on different machines, possibly allowing you to do the compilation faster.
In the last part of the assignment you will add signal processing.
Each of the parts of this assignment should be done in a separate directory.
Read the entire assignment before writing any code.
Part 0
If you have not already done so, get assignment 3 to work correctly.
Part 1
Get a copy of pipeserver.c from Chapter 6 of USP and rename it
pipecompiler.c.
Modify pipecompiler so that it takes
two fifo names as command line parameters, requestpipe and
replypipe.
Each will be created if necessary
and opened for both reading and writing. Instead
of calling copyfile, it starts an infinite loop.
In the loop it reads a line from the requestpipe and executes the
line as you did in execute_line from assignment 3. It then calls
wait_for_completion
and sends a single character to the replypipe, a '0' (ASCII code 48)
for success or a '1' (ASCII code 49) for failure.
Note that wait_for_completion returns 0 or 1 (ASCII codes 0 and 1)
while pipecompiler uses printing
characters. (This makes testing simpler.)
Change the usage message in pipecompiler.
Remove any print messages from wait_for_completion.
Note that once pipecompiler enters the loop,
it never exits, even if an error occurs.
Test this by using cat in one window to send lines to the requestpipe and cat in another window to read from the replypipe.
Part 2
Modify your mymake from assignment 3 so that instead of calling
execute_line
it uses two named pipes, a requestpipe and a replypipe.
Pass the names of these pipes on the command line. Your program will now have
three command line parameters, a makefile name, the replypipe name,
and the requestpipe name in this order.
Open the requestpipe for writing and the replypipe for reading. Pass the requestpipe file descriptor to a new function: execute_line_fd to send the line to the pipe. The function execute_line_fd will have two parameters, the line to send (a string) and the the file descriptor. The line should contain the newline. Do not send the string terminator to the pipe.
Write a new function: wait_for_completion_fd which takes 2 parameters, a file descriptor and count. It reads count bytes from the file descriptor and returns 0 if all were successful and 1 otherwise. You will be calling this function with the replypipe file descriptor as one of its parameters. You will need to keep track of the number of executions that are pending so that when a blank line is read, you can pass the appropriate count to wait_for_completion_fd. Your mymake program should terminate with an appropriate error message if wait_for_completion_fd returns failure.
Put all of the new functions you write in your makeutil.c file.
Part 3
In Part 2, all lines were sent to the same requestpipe.
Now we will use an
arbitrary number of pipes passed as the third, fourth, etc. command
line arguments. Start by opening all of the pipes and saving the file
descriptors of the requestpipes in an array.
There will still be only one replypipe.
As executions are required, send each one to a
different pipe until all pipes are used. Then start again with the first
requestpipe.
Do this until a blank line comes in. Keep track of the total number
of executions pending. When a blank line comes in,
call wait_for_completion_fd with the appropriate count. After this,
the next request will go to the first requestpipe.
Part 4
Add a signal handler for SIGUSR1.
Start the program by displaying the process
ID and setting up the signal handler. The signal handler will display the
number of pending executions on each requestpipe.
For each pipe, the name of the pipe and the count of pending executions
will be displayed. For this assignment you are allowed to use fprintf
in the signal handler. Put the handler in the mymake.c file.
Note: if you cannot get Part 3 to work, you can do Part 4 based on Part 2. There will only be one pipe displayed along with the number of pending executions.
Questions:
Testing your program.
You are responsible for creating tests cases for testing your program.
After you have done this, copy your mymake and pipecompiler
executables into a clean
directory and untar
this file in that directory.
If you have completed Part 3 successfully, open three windows in this directory.
In two the the windows execute:
./pipecompiler request1 reply and
./pipecompiler request2 reply.
In the third window, execute each of the following. In each case
save the output from all three windows.
./mymake mymakefile1 reply request1 request2
./mymake mymakefile2 reply request1 request2
./mymake mymakefile3 reply request1 request2
./mymake mymakefile4 reply request1 request2
If you have Part 4 also working, execute
./mymake mymakefile5 reply request1 request2
You must make sure there are no additional copies of mymake running
on your machine, or the test programs will not be able to send signals to
your program. Make sure your program is receiving the signals sent by
this final run. If you cannot figure out what is wrong, see me.
If you have Part 2 working, but not part 3, run the first four tests using 2 windows, one running the first pipecompiler and the other running the four tests above, omitting the last command line parameter.
Important:Before running each test, make sure that the reply pipe is
empty. You can do this by using ls -l to see the amount of data
in the pipe. If it is not empty, execute
cat reply
and then use CTRL-C to terminate the cat.
Be sure to clearly label the output of each of the windows for the tests that you turn in.
If a part of this assignment is not completely working, you must describe in detail exactly how far you got in trying to get it to work, what you tested, and what results you got from these tests. This is necessary if you want to receive partial credit for the work you did.