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

void handler(int signo)
{
    printf("Into handler\n");
    while(1);
}
int main()
{
    struct sigaction act;
    act.sa_handler = handler;
    act.sa_flags = 0;
    sigemptyset(& act.sa_mask);
    sigaction(SIGINT, &act, NULL);
    while(1);
    return 0;
}

After catching the KeyboardInterrupt once, when I press "Ctrl+C" again, SIGINT is not handled... I intend that "Into handler" should be printed each time I press "Ctrl+C".

I want to catch SIGINT inside the "SIGINT handler()" itself..

shadyabhi
  • 16,675
  • 26
  • 80
  • 131

5 Answers5

12

You need to set SA_NODEFER on sa_mask to catch the same signal as the one you're currently handling:

SA_NODEFER: Do not prevent the signal from being received from within its own signal handler. SA_NOMASK is an obsolete, non-standard synonym for this flag.

Mark Brackett
  • 84,552
  • 17
  • 108
  • 152
  • Beware: this doesn't guarantee that you won't lose signals! If your process gets multiple, non-realtime signals of the same type while it isn't on time slot or in uninterruptable kernel call, then the second (and further) signals will be lost. – peterh Sep 14 '15 at 11:45
9

What you are doing seems like a very bad idea, though, and it might be better to simply set a flag from the handler and return from it, and then do the printing from main.

You need to set SA_NODEFER or otherwise re-enable the signal within the signal handler itself because otherwise the signal gets blocked or switched back to its default behavior right before the call to the handler.

Calling printf from a signal handler is undefined behavior. It may crash your program. The list of functions that you actually can safely call from a signal handler is very limited. I need a list of Async-Signal-Safe Functions from glibc

Community
  • 1
  • 1
Tronic
  • 10,250
  • 2
  • 41
  • 53
  • +1 on the "seems like a very bad idea". In general, keeping your signal handlers as short and simple as possible is the way to go. – David Gelhar Mar 10 '10 at 17:09
  • thats why I wrote "sigemptyset(& act.sa_mask);" so that no signal is masked.. Where am I wrong? – shadyabhi Mar 10 '10 at 17:09
  • Actually, I want to learn "how to catch a particular signal inside its own signal handler?". thats why I asked the question – shadyabhi Mar 10 '10 at 17:10
  • 1
    The signal is blocked (or handler changed to SIG_DFL) right before the signal handler is called. What you set before that (in main) has no effect. – Tronic Mar 10 '10 at 17:12
  • As it says in the man page, it depends on the implementation. On Linux it simply blocks the signal before calling the handler and unblocks after the handler returns. – Tronic Mar 10 '10 at 17:21
3

Using the printf function within a signal handler is not exactly a good idea to use as it can cause behavior that is undefined! The code sample is missing a vital bit for the signal handler to work....Have a look at my blog about this here on 'Q6. How to trap a Segmentation fault?'

Also, you need to replace the while loop with something more robust as a way to quit the program while testing the signal handler...like...how do you quit it?

t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • I have just started reading about signals... So, whats the proper way? – shadyabhi Mar 10 '10 at 17:30
  • Look at the code, you will 'sigemptyset', then the flags is set, and 'sigaction(SIGINT, &sigact, (struct sigaction *)NULL);' is called after it...which traps the SIGINT..you are setting the flags before calling 'sigemptyset'..btw this was used in production environment and works happily under AIX... – t0mm13b Mar 10 '10 at 17:33
2

You can use something like this instead of printf:

const char *str = "Into handler\n";
write(1, str, strlen(str));

The function write(..) is safe to be called from signal hanlder. Don't forget to include unistd.h header to use it.

Bowdzone
  • 3,827
  • 11
  • 39
  • 52
iAndrew5
  • 21
  • 1
  • 1
    You are probably more safe referring to `stdout` rather than `1` as a variety of means could cause this number to change. – RastaJedi Feb 03 '17 at 01:17
1

The "while(1)" in handler is preventing the first service call from ever returning. Remove that and subsequent interrupts should cause handler to be called again.

An interrupt service routine should not prevent the calling thread from returning.

Adam Holmberg
  • 7,245
  • 3
  • 30
  • 53