Wednesday, February 15, 2006

Signal Handler

Consider that you have written a C program. Compile that and run it on a Linux Machine. When the program is executing, press Ctrl + C, the program execution stops. Suppose, if someone asks you to avoid this kind of termination of your program, What will you do?

First we can see what exactly happened when you pressed Ctrl + C. When Ctrl + C is pressed, a signal is generated. Now, what is a signal?? Signals are software interrupts sent to a process for notifying the process about some events. They interrupt whatever the process is doing at that time, and force it to handle them immediately. Each signal has an integer number that represents it (1, 2 and so on), as well as a symbolic name that is usually defined in the file /usr/include/signal.h.

You can write a signal handler for a particular signal. This signal handler function gets called when that particular signal occurs. The operating system transfers the control directly to this signal handler and once the signal handler has finished executing, the control returns back to whatever line of code that was executed previously. So how to you pass signals? well, Ctrl + C is just one method of passing a signal. We can do the same by using kill - or through the system call like kill(PID, SIGNAL).

To write your own signal handler, you need to use the following function.

void (*signal(int sig, void (*func)(int)))(int);

I know this is looking pretty complex. But the usage is not all that difficult. Signal function actually returns a function pointer. The first argument is the Signal number for which this particular signal handler has been written. Next is the pointer to the signal handler function. The signal handler function should take only one interger argument and should not return anything.

Eg:
signal (SIGINT, sig_int_handler);

void sig_int_handler(int sig)
{
// your code goes here.
}

The signal call returns the previous signal handler pointer in case of success or SIG_ERR in case of failure. so check for the return value.
if (signal (SIGINT, sig_int_handler)==SIGERR)
{
printf("Error handling signal");
exit(1);
}

So consider you have written your signal handler to catch SIGINT (consider that it prints some warning msg) and program execution continues. When you run your program, and if Ctrl + C is pressed( which is same as SIG_INT) the signal handler function is called, so a warning is displayed and the program execution continues. When the user presses Ctrl + C again, now the program terminates. What happened? Why did it terminate?

Every signal has a default signal handler function which is called when you dont provide a user defined signal handler function. But here we have provided our signal handler then whats the problem? well, once the signal handler function is called, the pointer to the signal handler function is actually reset to the default signal handler function. So how to overcome this problem? This is simple. In your signal handler function, again set the signal handler back to the user defined signal handler function.

void sig_int_handler(int sig)
{
signal (SIGINT, sig_int_handler);
//your code goes here.
}

once a signal appears, the signal handler is called and the signal handler pointer is reset to default signal handler. Now the control comes to the signal handler function, here we are saying that the signal handler for SIG_INT is sig_int_handler. So we are again setting the signal handler function. This avoids the termination of program when Ctrl + C is pressed two time or more.

One concern here is if the signals occur at a rate faster than the time taken for the process to enter the signal handler function and reset the signal handler pointer back to the user defined signal handler function, then the program may actually call the default signal handler and terminate!!!

3 comments:

  1. I have 2 questions here...

    1) How does this work in a Windows machine?
    2) Headerfiles to be inculded for executing the same?

    ReplyDelete
  2. The API for Windows machine is defined in Winsock.dll but 'm not too familiar with IPC handling in Windows. Check some website for that.

    ReplyDelete
  3. Hi, thank you for the post. I am new to signals. What if I want to pass an argument to the signal function.
    For example I have a large object in an (infinite) loop and I want to save it. So in principle I should pass the object to the signal function. How should I do this?

    Or the way to do it is to set a global variable flag after the function call and save the object in the loop after checking that global variable?

    Thanks.

    ReplyDelete