Sample Signal Handler in Linux Programming Interface

The following example is from the Michael Kerrisk Linux programming interface

static void sigHandler(int sig){
    printf("Ouch!\n");
}

int main(int argc, char *argv[])
{
    int j;

    if (signal(SIGINT, sigHandler) == SIG_ERR)
    errExit("signal");

    for (j = 0; ; j++){
        printf("%d\n", j);
        sleep(3);
    }
}

      

the print "Ouch!" to the terminal when the user types Control-C (CTRL + C); in the author's own example, he types it twice before finally leaving the terminal with Control - \ (CTRL + \).

When I do this, the program works as expected only the first time I execute CTRL + C. If I type it a second time, as the author does in his example, my program exits the terminal - it does not print "Ouch!" and it doesn't keep running (loop).

I used the exact same code that is here on the book's website:

Ouch.c

+3


source to share


2 answers


Usually you signal

need to reinstall the signal handler. Otherwise, it deactivates SIG_DFL (the default action corresponding to the signal). The default action for SIGINT

is to end the program.

Please note that printf(3)

this is not one of the asynchronous functions. So you can write (2) to do the same. See the POSIX List of Async Security Features.

Reinstallation should work as expected:

static void sigHandler(int sig){
    signal(SIGINT, sigHandler);
    write(STDOUT_FILENO, "Ouch!\n", 6);
}

      

This is one of the reasons why you should avoid signal

and use sigaction

. The above behavior is not universal across all platforms. So it is possible that the platform you are working on is not what the author checked my code against, or you are using a different Linux kernel.



The behavior in which you need to reinstall your signal handler after receiving a signal is system V behavior. But BSD semantics does not need to be reinstalled. Until recently Linux exhibited System V behavior, but it seems to have been fixed in the latest kernel, and I don't see it on my 3.19 kernel, but I can see the 2.6.32 kernel (significantly older).

Signals documentation says:

 The situation on Linux is as follows:

   * The kernel signal() system call provides System V semantics.

   * By default, in glibc 2 and later, the signal() wrapper function
     does not invoke the kernel system call.  Instead, it calls
     sigaction(2) using flags that supply BSD semantics.  This default
     behavior is provided as long as the _BSD_SOURCE feature test macro
     is defined.  By default, _BSD_SOURCE is defined; it is also
     implicitly defined if one defines _GNU_SOURCE, and can of course be
     explicitly defined.

   * On glibc 2 and later, if the _BSD_SOURCE feature test macro is not
     defined, then signal() provides System V semantics.  (The default
     implicit definition of _BSD_SOURCE is not provided if one invokes
     gcc(1) in one of its standard modes (-std=xxx or -ansi) or defines
     various other feature test macros such as _POSIX_SOURCE,
     _XOPEN_SOURCE, or _SVID_SOURCE; see feature_test_macros(7).)

      

So, you can get by by defining _BSD_SOURCE

to get BSD semantics. So the behavior you are seeing is mostly due to the fact that signal

your system follows System V semantics and recent Linux (and it probably checked Kerrisk) follows BSD semantics.

+5


source


you shouldn't use printf () in signal and exception handlers because they are not reentrant. printf also buffers data in memory before putting it into the console, so using fflush () will help print, but is not recommended. for testing purposes, use a counter (flag) in the handler and use an external printf handler. don't use signal () to register a handler, as every unix flavor (BSD, Linux) doesn't provide the same implementation. Use sigaction instead.



0


source







All Articles