Slaus
Slaus

Reputation: 2230

Questions about catching Unix signals

The following code catches the "SIGINT" signal only once and then interrupts (program exists):

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

void IntHandler(int value);

void CatchIntSignal()
{
    struct sigaction intAction;
    intAction.sa_handler = IntHandler;
    sigemptyset(&intAction.sa_mask);
    intAction.sa_flags = 0;
    //if to uncomment any of "0" or "SIG_IGN" - IntHandler will be never called:
    //intAction.sa_sigaction = 0/*SIG_IGN*/;
    if(sigaction(SIGINT, &intAction, NULL) != 0)
    {
        printf("sigaction() failed.\n");
    }
}

void IntHandler(int value)
{
    printf("IntHandler(%d)\n", value);
    //uncommenting this does not help:
    //CatchIntSignal();
}

int main()
{
    CatchIntSignal();
    getchar();
    return 0;
}

How must I modify this code to preserve program's exit after SIGINT catching? If to set intAction.sa_sigaction to 0 or to SIG_IGN - IntHandler will never be called - but why? Which undefined value does it have to say system that "it's necessary to call IntHandler"? If I will set some handler to intAction.sa_sigaction - this handler will be called (but IntHandler will not). How does system know that I did set something to intAction.sa_sigaction?

Upvotes: 1

Views: 968

Answers (3)

HJW
HJW

Reputation: 23453

After you have caught the interrupt signal and handled in your catch codes, you need to set the handling back to SIG_DFL.

EDIT: Ignore please. This is applicable only to the old unix signal().

Upvotes: 0

zwol
zwol

Reputation: 140866

Your problem is that the sa_handler and sa_sigaction fields of struct sigaction are actually the same field. Quoting the (OSX) manpage for sigaction(2):

 struct  sigaction {
         union __sigaction_u __sigaction_u;  /* signal handler */
         sigset_t sa_mask;               /* signal mask to apply */
         int     sa_flags;               /* see signal options below */
 };

 union __sigaction_u {
         void    (*__sa_handler)(int);
         void    (*__sa_sigaction)(int, struct __siginfo *,
                        void *);
 };

 #define sa_handler      __sigaction_u.__sa_handler
 #define sa_sigaction    __sigaction_u.__sa_sigaction

So your assignment to sa_sigaction is overwriting the handler you already set. You should just set sa_handler and leave sa_sigaction alone. This is how CatchIntSignal should read:

void CatchIntSignal()
{
    struct sigaction intAction;
    intAction.sa_handler = IntHandler;
    sigemptyset(&intAction.sa_mask);
    intAction.sa_flags = SA_RESTART;
    if(sigaction(SIGINT, &intAction, NULL) != 0)
        printf("sigaction() failed: %s\n", strerror(errno));
}

(You may need to add #includes of string.h and errno.h to get the strerror(errno) bit to compile. Always include strerror(errno) in error messages triggered when system calls fail.)

(CORRECTION: added SA_RESTART to flags per ninjalj.)

Upvotes: 4

Jonathan Leffler
Jonathan Leffler

Reputation: 755064

Your trouble is probably that the system call is interrupted, so the getchar() returns, probably with EOF. And the next thing the program does is exit...

So, you could try checking what getchar() returns, reset the error status on stdin, and call getchar() again to get the next signal.

Upvotes: 2

Related Questions