This homework is due on Tuesday, February 23, at 11:59:59 PM (Eastern standard time). You must use submit to turn in your homework like so: submit cs421_jtang hw2 evote.c candidate.c
Your programs must be named evote.c and candidate.c, and they will be compiled on Ubuntu 14.04 as follows:
gcc --std=c99 -Wall -O2 -o evote evote.c gcc --std=c99 -Wall -O2 -o candidate candidate.cThere must not be any compilation warnings in your submission; warnings will result in grading penalties. In addition, each code file must be properly indented and have a file header comment, as described on the coding conventions page.
Due to UMBC policy, you may not use the GL systems
for this assignment, because you will be using
the fork()
system call.
In this homework, you are writing an e-voting system for the upcoming presidential primaries. The system consists of two programs. The user interface is handled by evote. The candidates that may be voted for are represented by multiple instances of candidate.
The evote program will be divided into several parts as follows. Begin by inspecting the command line arguments. There must be exactly four arguments (plus the program name itself); if not then display an error message and quit. These four arguments are the names of candidates to appear on the ballot.
Next, create four unnamed pipes by calling
the pipe()
function four times. Store those file
descriptors somewhere convenient.
Third, call fork()
four times, to create
four (and only four!) child processes. Each child
is associated with one of the unnamed pipes; it is up to you to
figure out how to do this.
In the parent
process, close the
reading end of all four pipes and then display the PIDs of its
child
processes; use
the %ld
specifier when printing the value.
In the child process, close the writing the ends
of all unnamed pipes. Second,
use dup2()
to both
close stdin and duplicate the reading end of its pipe. Third
close the original reading end of its pipe. (That pipe can still be
read via the file descriptor that now occupies stdin.) Four,
call execlp()
to execute the candidate
program. While executing the program, pass the name of one of the
candidates from the original command line. In candidate.c,
set up a signal handler for signals SIGUSR1
and SIGUSR2, and set a global variable (representing number
of votes received) to zero. Then within a loop, read from the stdin
(which is really its unnamed pipe); this will cause the child
processes to block.
Within the parent process, in evote.c, display the following menu:
Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns
Read from the user a menu option, and then perform the requested action as below.
In the parent process, in evote.c, display the four candidates' names in a menu. Then read from the user a number, one through four. Send a SIGUSR1 signal to the candidate process with that name. If a child process has already terminated (see Part 4 below), then do not send the signal.
In the child process, in candidate.c, in its signal handler for SIGUSR1, increment by one the number of votes that candidate has received.
Afterwards, in the parent process, return to the main menu.
In the parent process, in evote.c, display the four candidates' names in a menu. Then read from the user a number, one through four. For that child process, close its unnamed pipe. If the child's pipe has already been closed, display an error message and return to the main menu.
In the child process, in candidate.c, its attempt to read
from stdin will result in returning an end-of-file value. Although
the proper term is
"suspending
a campaign", in reality the candidate is quitting the
election. Thus, in the child process call exit()
to
terminate.
Back in the parent process, call waitpid()
with the
child's PID, so as to reap the child. Afterwards, return to the main
menu.
In the parent process, in evote.c, display each child's PID and its process state. To get the process state, open and read from the file /proc/child_pid/stat, where child_pid is the PID of that child process. The state is the third field. Next send a SIGUSR2 signal to each child. If a child has already terminated (see Part 4 above), display the string "N/A" instead of its PID and process state, and do not send a signal.
In the child process, in candidate.c, in its signal handler for SIGUSR2, display both that process's candidate name (from its command line argument) and the number of votes received.
Afterwards, in the parent process, return to the main menu.
Process states are represented by various letters. Use your favorite search engine to look up the meaning of each possible letter.
One benefit of using computerized voting is that voter fraud is easily achieved, and this program is no different.
In the parent process, in evote.c, display the four candidates' names in a menu. Then read from the user a number, one through four. Then get from the user the number of votes to fraudulently add. Write to that child process's unnamed pipe a number of characters (it does not matter which one). If a child process has already terminated (see Part 4 above), then do not perform the write.
In the child process's reading loop, in candidate.c, increment its vote count for each character received.
Afterwards, in the parent process, return to the main menu.
In the parent process, in evote.c, for each child that is still alive, send it a kill message (as per Part 5 above). Finally, quit the program.
After you finish the code, as an experiment, temporarily modify evote.c so that child processes do not close the unnamed pipes' writing ends. Instead, have it just close its own pipe and not affect other pipes. Now try choosing this last menu option, and note that child processes are no longer terminating. In your evote.c file, add a comment block describing your observations. Then explain why a child process needs to close all writing ends, not just its own pipe, so that it can terminate. (Make sure you revert your changes prior to submitting your work.)
Here is a sample output from running the evote. Observe that because multiple processes are trying to write to the terminal simultaenously, their outputs are interleaved in non-obvious ways.
$ ./evote "Ronald Clump" "Raphael Cruise" "Mallory Klingon" "Ernie Flanders" Candidate "Ronald Clump" is pid 3371. Candidate "Raphael Cruise" is pid 3372. Candidate "Mallory Klingon" is pid 3373. Candidate "Ernie Flanders" is pid 3374. Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> (User enters 1) 0. Ronald Clump 1. Raphael Cruise 2. Mallory Klingon 3. Ernie Flanders Choose a candidate> (User enters 1) Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> (User enters 1) 0. Ronald Clump 1. Raphael Cruise 2. Mallory Klingon 3. Ernie Flanders Choose a candidate> (User enters 3) Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> (User enters 1) 0. Ronald Clump 1. Raphael Cruise 2. Mallory Klingon 3. Ernie Flanders Choose a candidate> (User enters 3) Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> (User enters 3) Ronald Clump: pid 3371 state S Raphael Cruise: pid 3372 state S Mallory Klingon: pid 3373 state S Ernie Flanders: pid 3374 state S Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> I am Mallory Klingon and I have 0 vote(s). I am Raphael Cruise and I have 1 vote(s). I am Ronald Clump and I have 0 vote(s). I am Ernie Flanders and I have 2 vote(s). (User enters 4) 0. Ronald Clump 1. Raphael Cruise 2. Mallory Klingon 3. Ernie Flanders Choose a candidate> (User enters 0) Number of votes to add> 999 Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> (User enters 2) 0. Ronald Clump 1. Raphael Cruise 2. Mallory Klingon 3. Ernie Flanders Choose a candidate> (User enters 1) Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> (User enters 3) Ronald Clump: pid 3371 state S Raphael Cruise: N/A Mallory Klingon: pid 3373 state S Ernie Flanders: pid 3374 state S Main Menu: 1. Cast ballot 2. Suspend campaign 3. Show vote counts 4. Commit voter fraud 5. End all campaigns Choose an option> I am Ronald Clump and I have 999 vote(s). I am Ernie Flanders and I have 2 vote(s). I am Mallory Klingon and I have 0 vote(s). (User enters 5)
strtok()
or strsep()
to
parse the stat file. Do not assume PIDs will only be
three, four, or even five digits long; you have to parse the
file.
read()
returns -1 and errno
will be set to
EINTR. Be sure
you handle
this situation.
Sorry, there is no extra credit available for this assignment.