CS 3733 Operating Systems, Fall 2008 Assignment 4


Due Friday, Oct. 31 and Friday, November 7

For the last three assignments you will by writing a parallel make program. In this assignment, child processes will communicate using pipes. In Assignment 5, thread will communicate with shared variables. In Assignment 6, processes on different machines will communicate over a network.

You should read over the entire assignment and the cover page before write a significant amount of code. There are questions to be answered on the back of the cover page.

Each time you start a new part of the assignment, create a new directory and copy all of the files from the previous part into this directory. This way if something goes wrong, you can fall back to the previous working part of the assignment.

Part 0
Make a new directory for this assignment. Create two C source files, one called makelib.c and the other called makechild.c. For now, makelib.c will contain one function, compile which takes two string parameters and returns an int. For this part of the assignment, compile will always return 1 and just print its two parameters separated by a blank on a single line. Make a file called makelib.h which will contain prototypes for all of the public functions in makelib.c. Include this in all C source files.

The makechild.c file will contain a main function. It will take an arbitrary number of command line parameters. The program starts by printing an identifying string containing your name, such as
makechild written by S. Robbins
followed by the command line parameters on a second line, with the parameters separated by a single blank.

The main program then calls compile once for each command line parameter. The first parameter is the path of the C compiler, and the second is a command line parameter. For each call, the main program will print a message containing the command line parameter used and the return value. You may hard code the path of the C compiler into your main program, but put it only in one place near the top of the file.

Part 1
In this part the command line parameters will be interpreted as the names of C source files without the .c extension.

Rewrite compile so that after printing out its parameters, it forks a child to exec the C compiler to compile the second parameter into an object file (extension .o) with the same name. The first parameter to compile should be the path of the C compiler. The parent in compile waits for the child process to complete and then returns 1. Your program will need to create a string from the second parameter with the extension .c appended, along with the appropriate compiler options as necessary. Do not make any assumptions about the length of the parameters passed to compile and make sure you avoid any memory leaks.

For example, to create object files for this assignment, you would execute:
      makechild makechild makelib
Note: It is not recommended that you test your program using your program source code, especially if you do not have a backup copy.

Part 2
Modify compile so that it determines whether the compilation was successful. It can do this using the value returned by the child process. After waiting for the child to complete, compile returns 1 if successful and 0 if not.

Part 3
Modify the main program so that if all of the calls to compile are successful, it creates an executable from the object files created. It will do this by forking a child that will exec the C compiler. The executable should have the same name as the first command line parameter. A message should be printed indicating success or failure.

Part 4
So far, our make has not been done in parallel. The compile function does not return until the compile is complete. We will fix this here.

Add a function to makelib called childcompile. It takes three command line parameters and returns void. The first two parameters are as in compile and the last is an integer representing an open file descriptor. The childcompile functions forks a child. If the fork was successful, the parent process returns immediately. Otherwise it writes a byte to the pipe (indicating failure) and returns. The child process will call compile and write a single byte to the file descriptor. The byte will be the return value from compile, either a 0 or a 1.

Copy makechild.c into makechildparallel.c and modify it so that it does the following. After printing out its initial message, it creates a pipe. Instead of calling compile it calls childcompile using the pipe write file descriptor as the additional parameter. After all of the calls to childcompile it reads the appropriate number of bytes from the pipe. If all compiles were successful, it creates an executable file as before. Before exiting, the main program prints a message indicating whether the final compile and all of the intermediate compiles were successful.

In this part of the assignment, the compiles should be done concurrently. It is possible for the output from the various compiles to be interleaved. Do not worry about this problem at this time. (See Part 6.)

Extra Credit:
There are three ways to obtain extra credit on this assignment. The extra credit can help you if you did not do well on a previous assignment or on the first midterm exam. Each of the extra credit parts is independent. You can do any one, or a combination of them. For each of the extra credit parts that you do, you must write an explanation of how you implemented and tested your program. Describe in words the algorithm that you used in the implementation.

Part 5: Optional, For Extra Credit
Modify compile so that it only performs the compile if necessary. The compile is necessary if the object file does not exist, or it exists, but it is older than the source file. For some additional extra credit you can create the executable only when necessary. Explain what when necessary means in this case.

Part 6: Optional, For Extra Credit
Modify your program so that the main program can determine which of the individual compiles were successful and print an appropriate detailed message if only some of these compiles worked. The detailed message should include a list of which compiles were successful and which were not. Do not modify any of the methods you put in makelib. Add new methods if need be. You might need methods with additional parameters. You may assume that there are at most 100 files to compile, but if you do, the main program should check that this constraint is satisfied before starting the compiles.

Part 7: Optional, For Extra Credit
This part is independent of Part 5.
Modify your programs so that childcompile does not output anything to the screen, either directly or by a child or a process started by exec. The only output should be produced by the main program.
While this will only tell you how many files have errors and not where the errors are, you could do an ordinary make after your program fails. Since your program will have already compiled the pieces that can be compiled without error, the first file compiled by the make should produce an error.

Handing in your assignment
One Friday, October 31, you must hand in a progress report for parts 0, 1 and 2. The progress report will contain your source code and a statement of what has is working so far. Use this cover sheet for the progress report.

You should test each part of the assignment with at least three command line parameters. Do at least 2 tests for each (except for Part 0), one in which all compiles are successful and one in which some compiles fail. Test at least the cases in which the compile fails because a file was not found and because there was a compilation error. Your programs should also be able to handle a failed call to fork. Save the output produced.

Use this cover sheet. There are questions to be answered on the back of the cover sheet. Consecutively number all of the pages you turn in.