This homework is due on Thursday, September 29, at 11:59:59 PM (Eastern daylight time). You must use submit to turn in your homework like so: submit cs421_jtang hw2 team.c player.c
Your programs must be named team.c and player.c, and they will be compiled on Ubuntu 16.04 as follow:
gcc --std=c99 -Wall -O2 -o team team.c gcc --std=c99 -Wall -O2 -o player player.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 will be simulating a baseball game. The first file, team.c, is the main driver for this assignment, and it is responsible for handling the user interface. At startup, it spawns multiple players, each represented as instances of player.c. The process team then simulates a baseball being thrown between the various player processes, by sending POSIX signals.
The team.c program will be divided into several parts as follows. When the process begin, inspect its 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 your infield players: first base (1B), second base (2B), short stop (SS), and third base (3B), in that order.
Second, create four unnamed pipes. Each pipe will be associated with
a player (first pipe to 1B, second pipe to 2B, and so forth). Next,
call fork()
four times, to create four child
processes. The first child process will be 1B, second process will
be 2B, and so forth. Store the child processes' PIDs somewhere in
memory.
In each child process, call dup2()
to both
close stdin and duplicate the reading end of the pipe associated
with that child process. Next, close all pipes'
file descriptors. (The pipe associated with the process can still be
read via the file descriptor that now occupies stdin.) Third,
call execlp()
to execute the player
program. While executing the program, pass the associated player
name (from the original command line) and its position (1B, 2B, SS,
or 3B). Ensure the child process does not continue forking
additional processes!
In player, display its player number (i.e., the child
process's PID), name, and its
position. Use
the %ld
specifier when printing the PID. Next, set
up signal handlers for the signals SIGUSR1
and SIGUSR2
. Initialize a global variable to zero; this
number will hold the number of times that player has handled the
baseball. Then, open the file /dev/urandom
using open()
. The
process will obtain
pseudo-random numbers from that virtual file. Finally, read from
stdin (which is really its unnamed pipe); this will cause the child
process to block.
Back in the parent process, after it has spawned the four child
processes, close
the reading end of all four pipes. Then write the four player
numbers (i.e., child processes' PIDs) to the first pipe, in the
order 1B, 2B, SS, then 3B. Repeat writing PIDs to the other three
pipes. You may find
the dprintf()
function useful here. Store in memory the pipes' writing end file
descriptors along with the child processes' PIDs. In the end the
parent must track all four file descriptors and all four child PIDs.
Because player was reading from the pipe, it will be unblocked. Store the other three player numbers in an array. Read from stdin to make the process block a second time.
Within the parent process, in team, display the following menu:
Main Menu: 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game
Read from the user a menu option, and then perform the requested action as below.
In the parent process, in team, display the four players'
names in a menu. Then read from the user a number, one through
four. Send a SIGUSR1
signal to the player
process with that name.
In the child process, in player, in its signal handler
for SIGUSR1
, print a message including the player's
name and that he caught the ball. Increment by one the number of
times that player has handled the baseball.
Afterwards, in the parent process, return to the main menu.
In the parent process, in team, display the four players'
names in a menu. Then read from the user a number, one through
four. Send a SIGUSR2
signal to the player
process with that name.
In the child process, in player, in its signal handler
for SIGUSR2
, print a message stating giving that
player's name and that he caught the ball. Increment by one the
number of times that player has handled the baseball. Then, if that
player is the first baseman, do nothing else. Otherwise, read a
single byte from its previously opened handle
to /dev/urandom,
via read()
. Treat
the lower two bits as a random number from 0 through 3. Print a
message stating to which position the ball is being thrown (where
zero is 1B, one is 2B, two is SS, and three is 3B) and the target
player number. Then send a SIGUSR2
signal to that
player number (i.e., process ID). If the random number matches the
player's position, pick another random number. In other words, a
player will never throw the ball to himself. Again, once the first
baseman has caught SIGUSR2
, then cease sending signals.
Afterwards, in the parent process, return to the main menu.
In the parent process, in team, write a byte to all four unnamed pipes. It does not matter which byte is written.
Because player was reading from the pipe, it will be
unblocked. Display that player's name, position, and the number of
times that player has caught the ball (i.e., sum
of SIGUSR1
and SIGUSR2
signals receieved).
Afterwards, in the parent process, return to the main menu.
In the parent process, in team, close all four unnamed
pipes. Then use waitpid()
to wait for each child
process to terminate. After all children have ended, end the
program.
Because player was reading from the pipe, it will be unblocked. Upon detecting that the pipe was closed, the process terminates itself.
For this assignment, you are required to provide the following documentation. In your team.c file, add a comment block near the top that answers the following questions:
Question 1: Back in Part 4, players could indefinitely throw the baseball between themselves without ever throwing to 1B. As currently described, there is no way for team to know when 1B has caught the ball. Describe how you would modify your program files so that team will wait for 1B to catch the ball prior to returning to the main menu. Do not actually write the code; just describe how using pseudocode.
Question 2: Research Linux's virtual
file /proc/PID/stat. List all of the possible
process states and their one letter abbreviations. Then identify
which state(s) the 1B process is in when it is waiting for the ball,
and then which state(s) it is in when while handling
a SIGUSR2
signal.
Here is a sample output from running team. Observe that because multiple processes are trying to write to the terminal simultaneously, their outputs are interleaved in non-obvious ways.
$ ./team Davis Schoop Hardy Machado Main Menu: 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game #11765: Hardy (SS) #11764: Schoop (2B) #11763: Davis (1B) #11766: Machado (3B) Choose an option> (User enters 1) 1. Davis 2. Schoop 3. Hardy 4. Machado Choose a player> (User enters 2) Main Menu: 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game Schoop caught the ball. Choose an option> (User enters 1) 1. Davis 2. Schoop 3. Hardy 4. Machado Choose a player> (User enters 3) Main Menu: Hardy caught the ball. 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game Choose an option> (User enters 1) 1. Davis 2. Schoop 3. Hardy 4. Machado Choose a player> (User enters 3) Main Menu: Hardy caught the ball. 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game Choose an option> (User enters 3) Main Menu: Hardy (SS): 2 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game Davis (1B): 0 Schoop (2B): 1 Machado (3B): 0 Choose an option> (Users enters 2) 1. Davis 2. Schoop 3. Hardy 4. Machado Choose a player> (User enters 4) Main Menu: 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game Machado caught the ball. Throwing the ball to #11765 SS. Hardy caught the ball. Throwing the ball to #11766 3B. Machado caught the ball. Throwing the ball to #11764 2B. Schoop caught the ball. Throwing the ball to #11763 1B. Davis caught the ball. Choose an option> (User enters 3) Main Menu: Hardy (SS): 3 1. Throw ball directly to a player 2. Field ball 3. Show player statistics 4. End game Davis (1B): 1 Schoop (2B): 2 Machado (3B): 2 Choose an option> (User enters 4)
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.