Search code examples
csigaction

Setting user defined signal actions and defaults (macOS and Linux)


I need a function that allows to either specify a user defined signal action, to reset it to default, or to ignore the signal. The code so far is

int setsig(int signum,  void (*action)(int, siginfo_t *, void *)) {
  struct sigaction sig;

  sigemptyset (&sig.sa_mask);
  sig.sa_sigaction = action;
  sig.sa_flags = SA_NODEFER|SA_SIGINFO;

  return sigaction (code, &sig, NULL); 
}

This shall later be used in a code like

static void my_action (int, siginfo_t *, void *);

void (*mysignal)(int, siginfo_t *, void *);

if (some_condition) {
    mysignal = my_action;
} else if (some_other_contion) {
    mysignal = SIG_IGN;
} else {
    mysignal = SIG_DFL;
}
[…]

setsig(signum, mysignal);

However, this wrongly treats SIG_IGN and SIG_DFL as sigactions and not as sighandlers. Are there (portable) equivalents as actions? Or is there another way to have them handled in a similar way?


Solution

  • I think @Aconcagua's answer is more flexible (since it allows additional handlers of type void (*)(int) to be used), but if the only values of type void (*)(int) you need to handle are the special values SIG_IGN and SIG_DFL you could use a type-cast operator to convert them and add code to setsig() to check for these special values:

    #define SET_SIG_IGN ((void (*)(int, siginfo_t *, void *))SIG_IGN)
    #define SET_SIG_DFL ((void (*)(int, siginfo_t *, void *))SIG_DFL)
    
    int setsig(int signum,  void (*action)(int, siginfo_t *, void *)) {
      struct sigaction sig;
    
      sigemptyset (&sig.sa_mask);
      if (action == SET_SIG_IGN || action == SET_SIG_DFL) {
        sig.sa_handler = (void (*)(int))action;
        sig.sa_flags = SA_RESTART;
      } else {
        sig.sa_sigaction = action;
        sig.sa_flags = SA_NODEFER|SA_SIGINFO;
      }
    
      return sigaction (signum, &sig, NULL); 
    }
    
    static void my_action (int, siginfo_t *, void *);
    
    […]
        void (*mysignal)(int, siginfo_t *, void *);
        […]
        if (some_condition) {
            mysignal = my_action;
        } else if (some_other_contion) {
            mysignal = SET_SIG_IGN;
        } else {
            mysignal = SET_SIG_DFL;
        }
        […]
        setsig(signum, mysignal);
    

    This assumes that the values SIG_IGN and SIG_DFL of type void (*)(int) can be converted to a pointer to a function of another type and back again and compare equal to the original value in the same way that pointers to actual functions do (ref: C17 6.3.2.3 paragraph 8).