This homework is due on Tuesday, February 28, at 11:59:59 PM (Eastern standard 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.c(Note the above is dash, dash, "std=c99", and the other flags likewise are preceded by dashes.) There 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 part of an ice hockey game. In hockey, the five positional players and their abbreviations are:
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 driver then sends a POSIX signal to one of the processes, to simulate the puck pass.
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 one arguments (plus the program name itself); if not then display an error message and quit. This argument identifies the designated goal scorer. It will be one of C, LW, RW, D, or D2, case-sensitive.
Second, create five unnamed pipes. Each pipe will be associated with
a player (first pipe to C, second pipe to LW, and so forth). Next,
call fork()
five times, to create five child
processes. The first child process will be C, second process will be
LW, third is RW, fourth is D, and fifth is D2. Store the child
processes' PIDs somewhere convenient.
In each child process, after the fork()
, ensure
the child process does not continue forking additional
processes! Call dup2()
to both
close stdin and duplicate the reading end of the pipe associated
with that child process. Next, close all pipes'
file descriptor, for a total of 10 closes. 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 two command
line arguments:
In player, display its PID 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
puck. Then 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 five child processes, close the reading end of all five pipes. Then write something to all five pipes, to indicate that all child processes have been created. (The data written are irrelevant.)
Because player was reading from the pipe, it will be
unblocked. It is now responsible for finding the PIDs of the other
members of the hockey team. Read
from /proc/sys/kernel/pid_max; this is the maximum PID for
your system. Then try reading from the
file /proc/X/cmdline, where X ranges from 1 up to
the maximum PID. If the file can be read and it contains the name of
the player process, then store the PID for Part 3
below. During this search, skip its own PID. Afterwards, the process
should have discovered the four PIDs of its sibling processes. Now,
initialize
the pseudo-random
number generator. Do this by calling srand()
,
passing its own PID as the sole argument. Finally, enter a loop that
continuously tries to read from the stdin again; this will cause the
process to block again.
Within the parent process, in team, display the following menu:
Main Menu: 0. Pass puck to player 1. Show player statistics 2. End game
Read from the user a menu option, and then perform the requested action as below.
In the parent process, in team, display a submenu of the
five positions. Read from the user which position to pass the
puck. For the chosen player, send a SIGUSR1
signal to
the requested player process.
In the child process, in player, in its signal handler
for SIGUSR1
, print a message stating that it received
the puck. Increment by one the number of times that player has
handled the puck. If that process is the designated goal scorer
(from when team was invoked), then print a message saying
it scored a goal and do nothing more. Otherwise, randomly pick
another player (via rand()
). Send
a SIGUSR1
signal to that process.
Afterwards, in the parent process, return to the main menu.
In the parent process, in team, display a submenu of the
five positions. Read from the user which position to pass the
puck. For the chosen player, send a SIGUSR2
signal to
the requested player process.
In the child process, in player, in its signal handler
for SIGUSR2
, print a message stating its position and
how many times it has handled the puck (i.e., the number
of SIGUSR1
signals it received).
Afterwards, in the parent process, return to the main menu.
In the parent process, in team, close all five 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 3, players could indefinitely pass the puck between themselves without ever sending it to the designated goal scorer. As currently described, there is no way for team to know when the goal was scored. Describe how you would modify your program files so that team will wait for the goal to be scored, 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/X/stat. List all of the possible process states and their one letter abbreviations. Then identify which state(s) a player process is in when it is blocked against the pipe, and then which state(s) it is in while executing a signal handler.
Here is a sample output from running team. The parts that are bolded are outputs from player processes. Observe that because multiple processes are trying to write to the terminal simultaneously, their outputs are interleaved in non-obvious ways.
Main Menu: 0. Pass puck to player 1. Show player statistics 2. End game Choose an option> C has pid 6825 LW has pid 6826 D2 has pid 6829 D has pid 6828 RW has pid 6827 (User enters 0.) 0. C 1. LW 2. RW 3. D 4. D2 Choose a player> 0 Main Menu: 0. Pass puck to player 1. Show player statistics 2. End game Choose an option> C got the puck. RW got the puck. LW got the puck. (User enters 0.) 0. C 1. LW 2. RW 3. D 4. D2 Choose a player> (User enters 4.) Main Menu: 0. Pass puck to player 1. Show player statistics 2. End game Choose an option> D2 got the puck. D got the puck. RW got the puck. LW got the puck. (User enters 1.) 0. C 1. LW 2. RW 3. D 4. D2 Choose a player> (User enters 2.) Main Menu: 0. Pass puck to player 1. Show player statistics 2. End game Choose an option> RW touched the puck 2 time(s). (User enters 2.)
snprintf()
and asprintf()
may prove useful for this
assignment.
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.