Question
We will finish two programs: caller.c will make NUM_CHILDREN child processes. Each child process will run responder. Then parent process will send either SIGUSR1 or
We will finish two programs:
caller.c will make NUM_CHILDREN child processes. Each child process will run responder. Then parent process will send either SIGUSR1 or SIGUSR2 a randomly-chosen child. The child will either respond with SIGUSR1 or SIGUSR2. If the parent receives a different signal than it sent then it records that as a "flip". The parent then signals a different child process. It continues doing this for 60 seconds. Then it tells all child processes to stop by sending them SIGTERM. At the end it prints each flip probability of each child, and how many times the child actually did flip its signal.
Each child process runs responder. It is given a probability on its command line. When it is signaled with either SIGUSR1 or SIGUSR2, it sends the other signal to its parent with the given probability. It stops altogether when it receives SIGTERM.
Sample Protocol:
caller | | fork/execl |-----------> resp0 | | | | fork/execl |---------------|-----------> resp1 | | | | | | fork/execl |---------------|---------------|-----------> resp2 | | | | | | | | fork/execl |---------------|---------------|---------------|-----------> resp3 | | | | | | | SIGUSR1 | | | |---------------|-------------->| | | | | SIGUSR1 |same | | |<--------------|---------------| | | | | | | | | | | | | | | | | | | | | SIGUSR1 | | |---------------|---------------|-------------->| | | | | SIGUSR2 |flip! | |<--------------|---------------|---------------| | . . .
Assignment:
caller.c
/*-------------------------------------------------------------------------* *--- ---* *--- caller.c ---* *--- ---* *--- This file defines a program that launches child processes ---* *--- and sends signals to them. ---* *--- ---* *--- ---- ---- ---- ---- ----- ---- ---- ---- ---* *--- ---* *--- Version 1a Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ /* * Compile with: * $ g++ caller.c -o caller */ #include#include #include #include #include #include const int NUM_CHILDREN = 4; const int NUM_SECS_TO_RUN = 60; const int TEXT_LEN = 16; #define CHILD_PROCESS "responder" pid_t childPidArray[NUM_CHILDREN]; float probabilityArray[NUM_CHILDREN]; int countArray[NUM_CHILDREN]; int shouldRun = 1; int lastSignal = SIGUSR1; // PURPOSE: To respond to SIGALRM by telling the process running this program // to stop. Ignores 'sigNum'. No return value. void sigAlarmHandler (int sigNum ) { // YOUR CODE HERE } // PURPOSE: To send 'sigNum' to the child indexed by 'childIndex'. // No return value. void signalChild (int childIndex, int sigNum ) { sleep(1); printf("Sending %s to %d ", ((sigNum == SIGUSR1) ? "SIGUSR1" : "SIGUSR2"), childIndex ); // YOUR CODE HERE } // ONE OR TWO FUNCTIONS HERE // PURPOSE: To install the signal handler(s). No parameters. No return // value. void installSignalHandlers () { struct sigaction act; // YOUR CODE HERE } // PURPOSE: To initialize 'probabilityArray[]' and 'countArray[]'. No // parameters. No return value. void initializeProbAndCountArrays () { int index; for (index = 0; index < NUM_CHILDREN; index++) { probabilityArray[index] = ((float)(rand() % 256)) / 256.0; countArray[index] = 0; } } // PURPOSE: To launch 'NUM_CHILDREN' child processes, each of which runs // program "responder". No parameters. No return value. void launchChildren () { int index; // YOUR CODE HERE } // PURPOSE: To send 'SIGTERM' to all 'NUM_CHILDREN' child processes. No // parameters. No return value. void tellChildrenToStop () { int index; for (index = 0; index < NUM_CHILDREN; index++) { // YOUR CODE HERE printf ("Child %d: prob %g, count %d ", index,probabilityArray[index],countArray[index] ); } } int main () { // I. Application validity check: // (Nothing to do) // II. Run program: srand(getpid()); // II.A. Install signal handler(s): installSignalHandlers(); // II.B. Initialize arrays and launch children: initializeProbAndCountArrays(); launchChildren(); // II.C. Send initial signals: // YOUR CODE HERE signalChild(rand() % NUM_CHILDREN,lastSignal); // II.D. Do the program: while (shouldRun) sleep(1); // II.E. Tell children to stop: tellChildrenToStop(); // III. Finished: return(EXIT_SUCCESS); }
Type: | Name: | Purpose: |
---|---|---|
Array of pid_t | childPidArray | Holds the process ids of the children |
Array of float | probabilityArray | Holds the probability that each child process will flip its signal. |
int | shouldRun | Holds 1 while the program should still run, of 0 otherwise. |
int | lastSignal | Holds either SIGUSR1 or SIGUSR2, whichever was the last signal that was sent. |
void | sigAlarmHandler(int sigNum) | Tells this process to stop (you may want to change shouldRun!) |
void | signalChild(int childIndex, int sigNum) | Sends the child indexed by childIndex the signal sigNum. (You may want to use childPidArray[]!) |
You will want either 1 or 2 advanced handlers to handle SIGUSR1 and SIGUSR2. See below. | ||
void | installSignalHandlers () | Installs all signal handlers. Be careful! Some are simple, some are advanced. |
void | initializeProbAndCountArrays () | Initializes probabilityArray[] and countArray[]. Already done for you. |
void | launchChildren () | Makes all children. Their process ids are placed in childPidArray[]. All children run CHILD_PROCESS, and are given their flip probability as a string on the command line. |
void | tellChildrenToStop () | Sends SIGTERM to all child processes. Also prints out their flip probability and how many times they flipped their signal. (Important! Do not leave any Zombies, now!) |
int | main () | Runs the program (silly!) |
sigAlarmHandler()
Change shouldRun so that this program leaves the while loop and main(), and quits.
signalChild()
Make this function send signal sigNum to the child indexed by childIndex.
Either 1 or 2 functions to handle SIGUSR1 and SIGUSR2
These function(s) must be advanced handlers. It/They must:
Use childPidArray[] to find the index of the child. (Call it childIndex.)
Increment countArray[childIndex] if the signal that was receive was not lastSignal
Do this:
int nextChildIndex; printf("Received %s from %d ", ((sigNum == SIGUSR1) ? "SIGUSR1" : "SIGUSR2"), childIndex ); do { nextChildIndex = rand() % NUM_CHILDREN; } while (nextChildIndex == childIndex); lastSignal = theSignalThatWasJustReceived; signalChild(nextChildIndex,lastSignal);
installSignalHandlers()
Installs all signal handlers. Be careful! Some are simple, some are advanced.
initializeProbAndCountArrays()
Initializes probabilityArray[] and countArray[]. Already done for you.
launchChildren()
Have a loop that makes NUM_CHILDREN child processes and puts their process ids in childPidArray[]. Each child process should run CHILD_PROCESS with the flip probability given as a command line argument. To convert the floating point number to a string, say:
char text[TEXT_LEN]; snprintf(text,TEXT_LEN,"%g",probabilityArray[index]);
tellChildrenToStop()
Has a loop that sends SIGTERM to all child processes. (Important! Do not leave any Zombies, now!)
main()
Mostly written for you except that you must tell the Operating System to send SIGALRM to you NUM_SECS_TO_RUN seconds in the future.
responder.c
/*-------------------------------------------------------------------------* *--- ---* *--- responder.c ---* *--- ---* *--- This file defines a program that responds to SIGUSR1 and ---* *--- SIGUSR2 from its parents. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1a Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ /* * Compile with: * $ gcc responder.c -o responder */ #include#include #include #include #include #include int shouldRun = 1; float flipProb = 0.0; void sigTermHandler (int sigNum ) { // YOUR CODE HERE } // YOUR CODE HERE int main (int argc, char* argv[] ) { struct sigaction act; srand(getpid()); // YOUR CODE HERE while (shouldRun) sleep(1); return(EXIT_SUCCESS); }
Type: | Name: | Purpose: |
---|---|---|
int | shouldRun | Holds 1 while the program should still run, of 0 otherwise. |
float | flipProb | Holds the probability that this process will flip a SIGUSR1 to SIGUSR2, or vice versa. |
void | sigTermHandler(int sigNum) | Tells this process to stop (you may want to change shouldRun!) |
You will want either 1 or 2 simple handlers to handle SIGUSR1 and SIGUSR2. See below. | ||
int | main () | Runs the program (silly!) |
sigTermHandler()
Change shouldRun so that this program leaves the while loop and main(), and quits.
Write 1 or 2 simple signal handlers to handle SIGUSR1 and SIGUSR2.
Do this:
float thisProb= ((float)(rand() % 256)) / 256.0;
If (flipProb > thisProb) then the signal has flipped. Print "Flipped! " and send the opposite signal to the parent process.
If (flipProb <= thisProb) then the signal has not flipped. Print "Same " and send the same signal to the parent process.
main()
This should do several things:
Make sure that the command line argument for the flip probability is given on the command line. If it is not, then do: fprintf(stderr,"Missing probability argument"); exit(EXIT_FAILURE);
Convert the command line argument from a string into a float, and put its value in flipProb. The value of flipProb should be between [0.0 .. 1.0]. If it is not, then do: fprintf(stderr,"Bad probability argument"); exit(EXIT_FAILURE);
Install all signal handlers.
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started