Initial commit.
This commit is contained in:
commit
548d91460f
|
@ -0,0 +1,202 @@
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.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 a child process and waits for it to send
|
||||||
|
* signals back. If the parent process receives a signal from the
|
||||||
|
* child, the signal handler tells the parent what to do.
|
||||||
|
*
|
||||||
|
* To end the program, do a Ctrl + C.
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// See comment above function definition.
|
||||||
|
void sigHandler(int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main function of program.
|
||||||
|
*/
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Seeding rand().
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PID from fork, user signal number,
|
||||||
|
* and time to wait respectively.
|
||||||
|
*/
|
||||||
|
int pid, sig, waitTime;
|
||||||
|
|
||||||
|
// Forking off child process.
|
||||||
|
pid = fork();
|
||||||
|
|
||||||
|
// Error handling.
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR with fork.\n");
|
||||||
|
exit(1);
|
||||||
|
// Child process code.
|
||||||
|
}
|
||||||
|
else if (!pid)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Wait for random amount of time
|
||||||
|
* between 1 and 5 seconds.
|
||||||
|
*/
|
||||||
|
waitTime = (rand() % 5) + 1;
|
||||||
|
|
||||||
|
// Sleep for random time.
|
||||||
|
sleep(waitTime);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Randomly choose between SIGUSR1
|
||||||
|
* and SIGUS2.
|
||||||
|
*/
|
||||||
|
sig = (rand() % 2) + 1;
|
||||||
|
|
||||||
|
// SIGUSR1
|
||||||
|
if (sig == 1)
|
||||||
|
{
|
||||||
|
// Send the signal!
|
||||||
|
kill(getppid(), SIGUSR1);
|
||||||
|
}
|
||||||
|
// SIGUSR2
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Send the signal!
|
||||||
|
kill(getppid(), SIGUSR2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saying which process was forked off.
|
||||||
|
printf("Spawned child PID %d.\n", pid);
|
||||||
|
|
||||||
|
// Binding signal handlers.
|
||||||
|
signal(SIGUSR1, sigHandler);
|
||||||
|
signal(SIGUSR2, sigHandler);
|
||||||
|
signal(SIGINT, sigHandler);
|
||||||
|
|
||||||
|
// Loop for waiting on signals.
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
printf("Waiting...\n");
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for signals. Binded for all three signals
|
||||||
|
* concerned in this application: SIGUSR1 (user-defined
|
||||||
|
* signal 1), SIGUSR2 (user-defined signal 2), and
|
||||||
|
* SIGINT (keyboard interrupt signal ^C). Depending
|
||||||
|
* on which signal is being handled (specified by
|
||||||
|
* sigNum), the handler will do different things.
|
||||||
|
* This is driven by the if-else statement.
|
||||||
|
*
|
||||||
|
* @param sigNum, the identifying number of the signal
|
||||||
|
* sent and now being handled. According to the
|
||||||
|
* man page for signal:
|
||||||
|
* SIGINT = 2
|
||||||
|
* SIGUSR1 = 30, 10, 16
|
||||||
|
* SIGUS2 = 31, 12, 17
|
||||||
|
*/
|
||||||
|
void sigHandler(int sigNum)
|
||||||
|
{
|
||||||
|
// If we're dealing with SIGUSR1.
|
||||||
|
if (sigNum == SIGUSR1)
|
||||||
|
{
|
||||||
|
// Saying it's SIGUSR1.
|
||||||
|
printf("Received a SIGUSR1 signal.\n");
|
||||||
|
|
||||||
|
// Binding signal handler again.
|
||||||
|
signal(SIGUSR1, sigHandler);
|
||||||
|
|
||||||
|
// Done handling.
|
||||||
|
return;
|
||||||
|
// If we're dealing with SIGUS2.
|
||||||
|
}
|
||||||
|
else if (sigNum == SIGUSR2)
|
||||||
|
{
|
||||||
|
// Saying it's SIGUSR2.
|
||||||
|
printf("Received a SIGUSR2 signal.\n");
|
||||||
|
|
||||||
|
// Binding signal handler again.
|
||||||
|
signal(SIGUSR2, sigHandler);
|
||||||
|
|
||||||
|
// Done handling.
|
||||||
|
return;
|
||||||
|
// If we're dealing with SIGINT (^C).
|
||||||
|
}
|
||||||
|
else if (sigNum == SIGINT)
|
||||||
|
{
|
||||||
|
// Exit message.
|
||||||
|
printf(" received. That's it, I'm shutting you down...\n");
|
||||||
|
|
||||||
|
// Exiting.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
Loading…
Reference in New Issue