Ignoring Signals

Have you ever had your C code run amok and had to press Ctrl+C to cancel?

Yeah, I’ve never had that happen to me either.

But seriously, what happens when you press Ctrl+C? Do you know?

Internally, pressing Ctrl+C sends a termination signal to the program. This signal is just one of many that can communicate with a running program. In fact, all your programs are constantly scanning for signals. Some of these signals can be intercepted and acted upon.

As an example, the Ctrl+C signal is defined as SIGINT, the program interruption signal. I know of a few others, such as Ctrl+Z that exits a program temporarily. (And it can wreck havoc when your code doesn’t know how to handle it.) For this Lesson, I’ll stick with Ctrl+C.

One time Ctrl+C becomes necessary is when the code gets stuck in an infinite loop. Here’s a deliberate example:

#include <stdio.h>

int main()
{
    char a = 0;

    for(;;)
    {
        printf("%d\n",a);
        a++;
    }

    return(0);
}

The for loop in this code keeps outputting the value of char variable a, cycling between -128 and 127 over and over until you press Ctrl+C (send the SIGINT signal) to terminate the program. (The program can also be terminated by sending it the kill signal.)

By the way, the Ctrl+S and Ctrl+Q keyboard shortcuts don’t send signals. These commands pause and continue text output (respectively), but they’re not signals. Ctrl+C, however, is a signal, and it can be intercepted in your code by using the signal() function.

The signal() function is prototyped in the signal.h header file. Its format is odd:

(void) signal(type,funct);

The (void) typecast is required. The first argument, type, is a constant representing the signal to trap, such as SIGINT for Ctrl+C. The second argument is the name of a function elsewhere in your code that handles the signal. The function accepts a single int argument, traditionally named sig.

In the following code, the ctrap() function is called when Ctrl+C attempts to break the endless loop. Within the function, a message is output and program flow is paused until Enter is pressed. Then, a signal() function re-instates the SIGINT (Ctrl+C) signal, so that the endless loop can finally be terminated.

#include <stdio.h>
#include <signal.h>

void ctrap(int sig)
{
    puts("Ctrl-C intercepted!");
    getchar();
    /* restore the default */
    (void) signal(SIGINT,SIG_DFL);
}

int main()
{
    char a = 0;

    /* intercept Ctrl+C */
    (void) signal(SIGINT,ctrap);

    for(;;)
    {
        printf("%d\n",a);
        a++;
    }

    return(0);
}

If you run this code, press Ctrl+C and you’ll see output pause. Press Enter to continue, then press Ctrl+C a second time to terminate. (This action may not work on all systems.)

I’ve used the signal() function in a text-mode game I wrote. It captures the SIGTSTP signal, activated by pressing Ctrl+Z in a Unix, to suspend the program and use the shell. That way someone can suspend the game, do something in the shell, then return to the program (use the bg shell command) to continue the game.

If the Ctrl+Z (SIGTSTP) signal weren’t intercepted, the game gets suspended when the user presses Ctrl+Z, but upon return it’s confused and doesn’t know what to do. Only when captured properly, can the code successfully suspend itself and recover. This action is made possible, thanks to the signal() function and its interception of the SIGTSTP signal.

Leave a Reply