cis-452-lab-3/extra-credit.c

202 lines
5.1 KiB
C

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
/**************************************************************************
* 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;
}