1

I have tried this code.

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

void sighandler(int);

int main()
{
   signal(SIGINT, &sighandler);

   while(1) 
   {
      sleep(1); 
   }
   return(0);
}

void sighandler(int signum)
{
   printf("Caught signal %d, coming out...\n", signum);
   exit(1);
}

But when I press ctrl+c, it doesn't catch the signal. But when I make it run in background and send the SIGINT signal using kill command, it is working properly. Please help me anyone....

larsks
  • 277,717
  • 41
  • 399
  • 399
  • 2
    This has to do with your shell/terminal rather than your program – Dmitri Jul 30 '15 at 03:49
  • 2
    Check your terminal settings with `stty -a`. The `intr = ^c` part means the `INTR` character is control-c. The `isig` part means int, quit, and suspend special characters are enabled (when the terminal is in canonical (cooked) rather than raw mode). `stty` checks its stdin, so you can `stty -a < /dev/pts/NN` to check the terminal your program is running on, while it's actually running. – Peter Cordes Jul 30 '15 at 04:16
  • 1
    Check this excerpt from: http://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-a-signal-handler/16891065#16891065 It is not safe to call all functions, such as printf, from within a signal handler. A useful technique is to use a signal handler to set a flag and then check that flag from the main program and print a message if required. – Ishmeet Jul 30 '15 at 04:18
  • It's working fine in my system. As like Peter Cordes comment check with your terminal settings. – Karthikeyan.R.S Jul 30 '15 at 04:31

2 Answers2

1

printf and exit aren't safe to call inside a signal handler. See signal(7) for the limited things you can do.

The immediate cause of your program's malfunction is likely that the file buffer for stdout didn't get flushed.

This change should fix it:

void sighandler(int signum)
{
   char msg[] = "Caught signal, coming out...\n";
   write( STDOUT_FILENO, msg, sizeof msg );
   _exit(1); // Do not call atexit routines.
}

However, the better strategy is to avoid doing any real work inside the handler at all. Just set a flag and return.

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

void sighandler(int);
volatile sig_atomic_t gotsig = 0;
volatile sig_atomic_t signum;

int main()
{
   signal(SIGINT, &sighandler);

   while(!gotsig) 
   {
      sleep(1); 
   }
   printf("Caught signal %d, coming out...\n", signum);
   exit(1);
}

void sighandler(int in_signum)
{
    gotsig = 1;
    signum = in_signum;
}
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
0

I remember reading that sigaction is the preferred function to use instead of signal, which is not as portable (pretty sure it was from The Linux Programming Interface which is an essential reference in my opinion).

My first thought was that Ctrl+C might not send the SIGINT signal if the system is not POSIX compliant, so I made a test program to see what relevant signals I can raise. The answer by @Potatoswatter popped up while I was trying this out and it seem more relevant to your immediate question of not getting output. Regardless, here is a POSIX friendly source file to test four signals (SIGINT, SIGTERM, SIGTSTP, and SIGQUIT):

#define _POSIX_C_SOURCE 200809L
#include <unistd.h>

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

void sigHandler(int sig);
static int did_catch = 0;
static int sig_caught = 0;

int main() {

    struct sigaction sa;

    /* buidl sigaction struct */
    sa.sa_handler = sigHandler;
    if (sigemptyset(&sa.sa_mask) != 0) { perror("\nsigemptyset"); exit(EXIT_FAILURE); }
    sa.sa_flags = 0;

    /* handle signals */
    if (sigaction(SIGINT, &sa, NULL) != 0) { perror("\nproblem adding SIGINT"); exit(EXIT_FAILURE); }
    if (sigaction(SIGTERM, &sa, NULL) != 0) { perror("\nproblem adding SIGTERM"); exit(EXIT_FAILURE); }
    if (sigaction(SIGQUIT, &sa, NULL) != 0) { perror("\nproblem adding SIGQUIT"); exit(EXIT_FAILURE); }
    if (sigaction(SIGTSTP, &sa, NULL) != 0) { perror("\nproblem adding SIGTSTP"); exit(EXIT_FAILURE); }

    /* wait for signal */
    while (!did_catch) {
        pause();
    }

    /* check caught signals */
    if (sig_caught == SIGINT) printf("\nsignal is SIGINT\n");
    else if (sig_caught == SIGTERM) printf("\nsignal is SIGTERM\n");
    else if (sig_caught == SIGQUIT) printf("\nsignal is SIGQUIT\n");
    else if (sig_caught == SIGTSTP) printf("\nsignal is SIGTSTP\n");
    else printf("\nsignal captured is not listed\n");

    return 0;
}

void sigHandler(int sig) {
    sig_caught = sig;
    did_catch = 1;
}

Hope this helps.

ChisholmKyle
  • 449
  • 3
  • 10
  • `sigaction` is POSIX. `signal` is part of the C language standard, so it is more portable. The C library, by the way, is also included in POSIX. – Potatoswatter Jul 30 '15 at 05:23
  • OK thanks. I found the section I was thinking of in [TLPI](http://man7.org/tlpi/). It's in section **22.7** and basically states that old unreliable UNIX implementations of `signal` such as System V and old glibc behave unreliably and differently than newer implementations (different semantics) so `sigaction` is more reliable with a clearly defined implementation. The linux [signal man page](http://man7.org/linux/man-pages/man2/signal.2.html) also suggests `sigaction`. In practice, I'd expect using `signal` is just fine on newer systems. – ChisholmKyle Jul 30 '15 at 05:48