Signal Handling
• An application program can specify a function
called a signal handler to be invoked when a
specific signal is received.
• When a signal handler is invoked on receipt of a
signal, it is said to catch the signal. A process
can deal with a signal in one of the following
ways:
• The process can let the default action happen
• The process can block the signal (some signals cannot be
ignored)
• the process can catch the signal with a handler.
• Each signal defined by the system falls
into one of five classes:
• Hardware conditions
• Software conditions
• Input/output notification
• Process control
• Resource control
• Macros are defined in <signal.h> header file for common
signals.
• These include:
• SIGHUP 1 /* hangup */
• SIGINT 2 /* interrupt */
• SIGQUIT 3 /* quit */
• SIGILL 4 /* illegal instruction */
• SIGABRT 6 /* used by abort */
• SIGKILL 9 /* hard kill */
• SIGALRM 14 /* alarm clock */
• SIGCONT 19 /* continue a stopped process */
• SIGCHLD 20 /* to parent on child stop or exit */
Signals can be numbered from 0 to 31.
Signal handlers usually execute on the current
stack of the process
This lets the signal handler return to the point that
execution was interrupted in the process
This can be changed on a per-signal basis so that
a signal handler executes on a special stack. If a
process must resume in a different context than
the interrupted one, it must restore the previous
context itself
• Receiving signals is straightforward with the function:
int (*signal(int sig, void (*func)()))()
Here the function signal() will call the func functions if the
process receives a signal sig.
Signal returns:
a pointer to function func if successful
or
it returns an error to errno and -1 otherwise.
• func() can have three values:
• SIG_DFL
– -- a pointer to a system default function SID_DFL(),
which will terminate the process upon receipt of sig.
• SIG_IGN
– -- a pointer to system ignore function SIG_IGN()
which will disregard the sig action (UNLESS it is
SIGKILL).
• A function address
– -- a user specified function.
SIG_DFL and SIG_IGN are defined in
signal.h (standard library) header file.
• Thus to ignore a ctrl-c command from the
command line. we could do:
signal(SIGINT, SIG_IGN);
• To reset system so that SIGINT causes a
termination at any place in our program,
we would do:
signal(SIGINT, SIG_DFL);
So lets write a program to trap a
ctrl-c but not quit on this signal
/*This program has two functions: main() which sets up the signal
handler (using the signal() call), and sigint_handler() which is the
signal handler, itself.
What happens when you run it?
If you are in the midst of entering a string and you hit ^C, the call to
gets() fails and sets the global variable errno to EINTR.
Additionally, sigint_handler() is called and does its routine, so you
actually see:
Enter a string:
the quick brown fox jum^CNot this time!
gets: Interrupted system call */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
int main(void)
{
void sigint_handler(int sig); /* prototype */
char s[200];
/* set up the handler */
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
perror("signal");
exit(1);
}
printf("Enter a string:\n");
if (gets(s) == NULL)
perror("gets");
else
printf("You entered: \"%s\"\n", s);
return 0;
}
void sigint_handler(int sig){
signal(SIGINT, sigint_handler);
/* reset it to this function */
printf("Not this time!\n");
}
Sending Signals -- kill(), raise()
There are two common functions used to send
signals:
int kill(int pid, int signal)
- a system call that send a signal to a process,
pid.
- If pid is greater than zero, the signal is sent to
the process whose process ID is equal to pid
- If pid is 0, the signal is sent to all processes,
except system processes.
kill() returns 0 for a successful call,
-1 otherwise and sets errno accordingly.
int raise(int sig);
sends the signal sig to the executing
program
raise() actually uses kill() to send the signal
to the executing program:
• kill(getpid(), sig);
• NOTE: that unless caught or ignored, the kill
signal terminates the process. Therefore
protection is built into the system.
• Only processes with certain access privileges
can be killed off.
• Basic rule: only processes that have the same
user can send/receive messages.
• The SIGKILL signal cannot be caught or ignored
and will always terminate a process
• For example kill(getpid(),SIGINT); would send
the interrupt signal to the id of the calling
process.
• This would have a similar effect to exit()
command. Also ctrl-c typed from the command
sends a SIGINT to the process currently being.
• unsigned int alarm(unsigned int seconds) --
sends the signal SIGALRM to the invoking
process after seconds seconds