Final exam / Assignment 5

advertisement
CSC 552 UNIX System Programming, Fall 2015
Dr. Dale E. Parson, Final exam programming project. 20% of course grade per first day handout.
This assignment is due via make turnitin from the final552pipeline/ directory by 11:59 PM on Saturday
December 12. I will not accept a late assignment.
Perform the following steps to get my handout from any Linux machine. The makefile requires you to ssh
into one of luna, dumbledore, or hermione for testing.
cd $HOME
# or start out in your login directory
cd ./UnixSysProg
cp ~parson/UnixSysProg/final552pipeline.problem.zip final552pipeline.problem.zip
unzip final552pipeline.problem.zip
cd ./final552pipeline
PART 1, Worth 80% of exam. There are 4 tests in the makefile within final552pipeline, each worth
20% of the exam. You can run “make test1” “make test2” “make test3” or “make test4” to run
individual tests, or “make test” to run them all.
Examine the documentation comments and function header in file include/pipeline.h. In the existing
pipelinelib/ subdirectory, you must create file pipelinelib/pipelinecmds.c and implement function
void runpipeline(int argc, char *argv[])
as documented in include/pipeline.h.
You can consult ~parson/UnixSysProg/runcat2/runcatlib/run1cmd.c1 to see my solution to assignment 2
that uses fork(), exec(), pipe(), and other system calls related to this project. This project does not need to
read() or write() any file descriptors. All reading and writing takes place in exec()’d children processes.
Here is the full list of library functions and system calls that I used in my exam solution:
perror
fprintf
exit
pipe
fork
execl
dup2
close
wait, WIFEXITED, WEXITSTATUS
man –s3 perror
man –s3 fprintf
man –s3 exit
man –s2 pipe
man –s2 fork
man –s3 execl
man –s2 dup2
man –s2 close
man –s2 wait
Here is a snapshot of make test from my solution to the project, interspersed with dataflow diagrams of
the pipelines constructed by runpipeline(). The pipelines do not show the parent process that forks each of
the children processes (circles or ellipses) appearing in the dataflow diagrams. The file descriptors
(STDIN_FILENO, STDOUT_FILENO and pipes) appear as external entities (boxes) in the dataflow
diagrams.
1
Also contained in ~parson/UnixSysProg/runcat2.solution.zip. page 1
/bin/bash -c "ls pipelinelib" > test1.ref
./pipeline "ls pipelinelib" > test1.out
diff test1.out test1.ref > test1.dif
# This shell command generates the reference file.
# This command tests your program.
# Compare their output, “cat test1.dif” to see diffs.
/bin/bash -c "ls pipelinelib include | wc -l" > test2.ref
./pipeline "ls pipelinelib include" "wc -l" > test2.out
diff test2.out test2.ref > test2.dif
/bin/bash -c "cat ./pipeline.c | pr -n | wc -c" > test3.ref
./pipeline "cat ./pipeline.c" "pr -n" "wc -c" > test3.out
diff test3.out test3.ref > test3.dif
bash -c './pipeline "ls bogusFileName" "wc -l" ; echo STATUS $? > test4.out'
ls: cannot access bogusFileName: No such file or directory
0
Child exited with status 2.
diff test4.out test4.ref > test4.dif
When function runpipeline() in the parent process detects a non-0 exit() value from the any child process
via wait(), the parent prints a message to stderr using fprintf and exit()s immediately; the parent process
exits with the same exit() value as the child. In the above test, the child exit()ed with a value of 2, which
page 2
is the value appearing in test4.ref. The following interactive shell command shows the same exit value;
the shell uses variable $? to hold the exit value of the most recently completed command.
$ ls bogusFileName
ls: cannot access bogusFileName: No such file or directory
[:-) ~/.../solutions/final552pipeline] echo $?
2
After you get each of test1 through test4 to pass correctly, you can
cp pipelinecmds.c pipelinecmdsN.bak
to save a working copy of your code to that point, where N is 1 or 2 or 3 or 4, depending on which test
passes. Alternatively, you can complete the assignment without creating these backup file copies.
PART 2, Worth 20% of exam.
In the final552pipeline/wordcaInC3/ is my working solution to assignment 3, which is the single-threaded
cellular automaton that uses the select() system call within the serverLoop function.
In WordCA.c function main() you must add a call to the signal system call (man –s2 signal; ignore the
comments about avoiding it; it works). It must catch signal number 6 (which is SIGABRT according to
man –s7 signal) by invoking a helper function that you must write. Your function must set variable
isShutdown to 1 (which is true).
Here is what the handout code prints when I invoke make tests to start an interactive server, and then exit
by hitting control-D for EOF.
aX,Y,(a|d|/|\),TEXT or rI(se[c[s]]|ms[ec[s]]|st[ates]) or p(l|s):
FINAL VALUE OF isShutdown is 0.
0.00user 0.00system 0:04.09elapsed 0%CPU (0avgtext+0avgdata 2944maxresident)k
80inputs+0outputs (1major+214minor)pagefaults 0swaps
/bin/rm -f /tmp/CSC552_*_parson.*
That output is correct, since serverLoop() does not set isShutdown to anything, leaving it at 0.
However, if I make tests and then run ps –fu parson in another window (use YOUR userid, not parson),
and find the process ID of the WordCA process:
$ ps -fu parson
UID
PID PPID C STIME TTY
TIME CMD
…
parson 14757 14756 0 18:38 pts/3 00:00:00 ./WordCA - 10 10 4
Running kill -6 14757 (or more generally, kill -6 PID) to send the signal 6 (SIGABRT) to the WordCA
process should result in this output, once the signal() catcher is working:
aX,Y,(a|d|/|\),TEXT or rI(se[c[s]]|ms[ec[s]]|st[ates]) or p(l|s): Server cannot select.: Interrupted system
call
FINAL VALUE OF isShutdown is 1.
0.00user 0.00system 2:06.03elapsed 0%CPU (0avgtext+0avgdata 3040maxresident)k
80inputs+0outputs (1major+220minor)pagefaults 0swaps
/bin/rm -f /tmp/CSC552_*_parson.*
page 3
The original handout code does not shutdown cleanly on signal 6. The signal aborts it, giving this error:
aX,Y,(a|d|/|\),TEXT or rI(se[c[s]]|ms[ec[s]]|st[ates]) or p(l|s): 0.00user 0.01system 0:11.60elapsed
0%CPU (0avgtext+0avgdata 2912maxresident)k
80inputs+0outputs (1major+212minor)pagefaults 0swaps
make: *** [tests] Error 6
Once you have everything above working correctly, run make test from the main final directory one last
time, then run make turnitin from that directory. I will not accept late assignments, I will not help to
debug this assignment, and I will not answer questions about any of the above after the December 9 class.
The only question I will answer after that class is if someone finds a statement above so ambiguous that it
demands clarification. In that case, I will email the reply to the class and post it in a D2L forum for the
final exam. This project is an exam.
CAVEATS for runpipeline():
A. A parent or child process that does not use a read or write side of a pipe() should close() that side of
the pipe(). It is critical to close() the write side of a pipe() if a process has it open and does not plan to
write to it. Otherwise, a reader or readers of the pipe() will never see EOF (end of file). They may
block indefinitely trying to read the pipe.
B. A Unix process that exit()s automatically closes all files.
C. You do NOT have to check the exit status of your close() system calls that are guaranteed to work on
obviously open fd’s. Otherwise, file include/pipeline.h states, “If any of the system calls within
runpipeline fails, it must perror() an error message and then exit(1) without returning.” Doing so is
extremely helpful during debugging.
D. My call to execl() uses “/bin/bash” as the command path and also uses “/bin/bash” as the first
command line argument; it uses “-c” as the next command line argument, just as assignment 2.
page 4
Download