Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Signal Handler Example in The Linux Programming Interface

The following example from The Programming Linux Programming Interface by Michael Kerrisk

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);
    }
}

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

When I do this, the program works as expected on only the first execution of CTRL+C. If I type it in for the second time, like the author does in his example, my program quits the terminal- it does not print "Ouch!" nor does it continue to run (looping).

I used the exact same code as given here, on the book's website:

Ouch.c

like image 515
8protons Avatar asked Oct 18 '25 19:10

8protons


1 Answers

Typically signal needs the signal handler to be re-installed. Otherwise, it defautlts to SIG_DFL (default action corresponding to the signal). The default action for SIGINT is to terminate the program.

Note that printf(3) is not one of the async-safe functions. So you could write(2) to to do the same. See the POSIX list of Async-signal-safe functions.

Re-installing it should make 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 instead. The above mentioned behaviour is not universal across platforms. So perhaps, the platform you are running is not what author tested his code on or you are using a different Linux kernal.

The behaviour where you need to re-install the signal handler upon receiving a signal is System V behaviour. But BSD semantics doesn't need re-installing. Until recently, Linux showed System V behaviour but it seems to have been fixed in the recent kernel and I do not see this on my 3.19 kernel but can see 2.6.32 kernel (considerably old).

Signal's documentation states:

 The situation on Linux is as follows:

   * The kernel's 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 could work around by defining _BSD_SOURCE to get BSD semantics. So behaviour you observe is mostly likely because the signal on your system follows System V semantics and recent Linux (and probably what Kerrisk tested it on) follows BSD semantics.

like image 190
P.P Avatar answered Oct 21 '25 09:10

P.P