Unix Signal Handlers

Signal Processing

In this lab, you will demonstrate your knowledge of signal processing in Unix (signal or
sigaction). You are required to write a C program that contains three signal handler
functions:
(1) The first is to handle the SIGINT (CTRL-C) signal. This signal handler should
increment a counter and when the program finally completes, the program should
output the number of times the user depressed CTRL-C. In addition, the signal handler
should also contain a MAX value (say 5) that is invoked if the user exceeds this
maximum. In this case, a message indicating that the MAX has been exceeded should
be output and the signal should not be reinstalled so the next instance will cause the
program to terminate.
(2) The second signal handler should deal with the SIGQUIT signal (CTRL-\). If the user
sends this signal, the signal handler should create a new process (fork). The child
process should print a message and then send a SIGUSR1 signal (using kill() see slide
9) to its parent then the child should terminate with no error code. The parent should
simply wait for the child to terminate.
(3) The final signal handler should catch the SIGUSR1 signal (sent by the child
process). This handler should print a message that the program is over and then exit.
The main program should contain a loop forever waiting for a signal (i.e. pause).
Sample output of your program might look something like:
[email protected]:~]$ ./lab5
Wait for another signal …
^CThis is the 1 time you pressed ctrl-c
Wait for another signal …
^CThis is the 2 time you pressed ctrl-c
Wait for another signal …
^CThis is the 3 time you pressed ctrl-c
Wait for another signal …
^CThis is the 4 time you pressed ctrl-c
Wait for another signal …
^\I am the child and I am sending a signal
Child sent a signal so I guess you are bored, have a great day!

Solution

 //Libraries

#include <signal.h> //The signal library

#include <stdlib.h> //standard library

#include <stdio.h> //printf Standard InputOutput Library

#include <unistd.h> //pid, cwd, fork

//Global Vars

staticintconst MAX_COUNT = 5; //Max number of sigints to recieve before removing the sigint handler

intsigintCounter = 0; //Used to show how many sigint signals recieved

pid_tchild_pid; //child process id

//Prototypes

voidsigintHandler(intsigint);

voidsigquitHandler();

voidsiguserHandler();

//Main

//Listen for the three different types of sigints (SIGINT, SIGQUIT, SIGUSR1)

int main(intargc, char* argv[])

{

if (!child_pid)

{

//Parent functionality

//Handlers

signal(SIGINT, sigintHandler); //ctrl-c

signal(SIGQUIT, sigquitHandler); //ctrl-slash

signal(SIGUSR1, siguserHandler); //user defined

//Forever loop while we wait for signals

do

{

printf(“Wait for another signal … \n”);

pause(); //wait

} while (1);

}

}

//SIGINT HANDLER (ctrl-c)

// Param: sigint the number emitted (1-3) : not used in this

voidsigintHandler(intsigint)

{

sigintCounter++; //increment the counter

//Check if we reached the total number of sigint counts

if (sigintCounter>= MAX_COUNT)

{

//Done

printf(“SIGINT: MAX has been exceeded\n”);

signal(SIGINT, SIG_DFL); //use the default sigint handler

} else

{

printf(“This is the %d time you pressed cntl-c\n”, sigintCounter);

signal(SIGINT, sigintHandler); //readd the custom handler

}

}

//SIGQUIT HANDLER (ctrl-\)

voidsigquitHandler()

{

//Fork the process and create a child process

if (!(child_pid = fork()))

{

// Child: Print message

printf(“I am the child(%d) and I am sending a signal to parent(%d)\n”, getpid(), getppid());

// Child: KILL() to parent

kill(getppid(), SIGUSR1); //send signal

exit(0); //child process exit

} else

{

//Parent message

printf(“Parent(%d): I have a child %d\n”, getpid(), child_pid);

}

}

//SIGUSR1 (sent by child process)

voidsiguserHandler()

{

printf(“Parent(%d): Child sent signal. We are finished\n”, getpid());

exit(0); //Exit parent process

}