#include #include #include #include #include #include /************************************************************************** * Authors: Gary Fleming, Amber McCloughan * Class: CIS452 - Operating Systems Concepts * Professor: Dr. Greg Wolffe * Date: 2/07/2019 * * Program that forks off two child processes and waits for them to send * back signals. If the parent receives a signal, the handler for that * signal tells them what to do. Uses POSIX signal handling instead of * ANSI signal handling. * * To end the program, do a Ctrl + C. ***************************************************************************/ // See comment above function definition. void sigHandler(int, siginfo_t*, void*); /** * Main function for the program. */ int main() { // Structs for sigaction. struct sigaction actionUsr1, actionUsr2, actionInt; // Forked PID and amount of time the child will wait. int pid, sig, waitTime; // Forking off the first child. pid = fork(); // Error handling. if (pid < 0) { fprintf(stderr, "ERROR with fork.\n"); exit(1); // Child process code. } else if (!pid) { // Seeding rand(). srand(time(NULL) + 1); // Loop for sending SIGUSR1. while (1) { // Getting random seconds. waitTime = (rand() % 5) + 1; sig = (rand() % 2) + 1; // Waiting for random seconds. sleep(waitTime); if (sig == 1) { kill(getppid(), SIGUSR1); } else { kill(getppid(), SIGUSR2); } } } // Saying which process was forked first. printf("Spawned child PID %d.\n", pid); // Forking off a second child. pid = fork(); // Error handling. if (pid < 0) { fprintf(stderr, "ERROR with fork.\n"); exit(1); // Child process code. } else if (!pid) { // Seeding rand(). srand(time(NULL) + 2); while (1) { // Getting random seconds. waitTime = (rand() % 5) + 1; sig = (rand() % 2) + 1; // Sleeping for random seconds. sleep(waitTime); if (sig == 1) { kill(getppid(), SIGUSR1); } else { kill(getppid(), SIGUSR2); } } } // Saying which child forked second. printf("Spawned child PID %d.\n", pid); // Set all bytes to 0. memset(&actionUsr1, 0, sizeof(struct sigaction)); memset(&actionUsr2, 0, sizeof(struct sigaction)); memset(&actionInt, 0, sizeof(struct sigaction)); /* * If SA_SIGINFO is specified in sa_flags, then * sa_sigaction (instead of sa_handler) specifies * the signal-handling function for signum. * (From the man page for sigaction.) */ actionUsr1.sa_flags = SA_SIGINFO; actionUsr2.sa_flags = SA_SIGINFO; actionInt.sa_flags = SA_SIGINFO; // Choosing the signal handlers. actionUsr1.sa_sigaction = &sigHandler; actionUsr2.sa_sigaction = &sigHandler; actionInt.sa_sigaction = &sigHandler; /* * Actually binding the signal handlers. * I figured out how to do this using the following article: * https://www.linuxprogrammingblog.com/code-examples/sigaction */ sigaction(SIGUSR1, &actionUsr1, NULL); sigaction(SIGUSR2, &actionUsr2, NULL); sigaction(SIGINT, &actionInt, NULL); // Loop for waiting on signals. while (1) { fprintf(stderr, "Waiting...\n"); pause(); } } /** * Signal handler for all signals. Parameter descriptions pulled * from the man page for sigaction. * * @param sigNum, number of the signal that caused invocation of the * handler. * @param siginfo_t*, pointer to a siginfo_t, which is a structure * containing further information about the signal. * @param ucontext, pointer to a ucontext_t structure, cast to void*. * The structure pointed to by this field contains signal * context information that was saved on the user-space stack by * the kernel. */ void sigHandler(int sigNum, siginfo_t *info, void *ucontext) { // If the signal was SIGUSR1. if (sigNum == SIGUSR1) { // Saying it's SIGUSR1 and telling who sent it. fprintf(stderr, "Received a SIGUSR1 from PID %d.\n", info->si_pid); // Done handling. return; } // If the signal was SIGUSR2. else if (sigNum == SIGUSR2) { // Saying it's SIGUSR2 and telling who sent it. fprintf(stderr, "Received a SIGUSR2 from PID %d.\n", info->si_pid); // Done handling. return; } // If the signal was SIGINT (^C). else if (sigNum == SIGINT) { // Goodbye message. char *message = " received. That's it, " "I'm shutting you down...\n"; // Printing goodbye message. fprintf(stderr, message); // Exiting. exit(0); } return; }