0

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?

olebole
  • 521
  • 4
  • 17
  • So; I need to handle my own action and `SIG_IGN` resp. `SIG_DFN` in a similar way. And since I need the additional info in `siginfo_t`, I can't use `signal()`. – olebole Apr 06 '23 at 10:11

2 Answers2

2

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).

Ian Abbott
  • 15,083
  • 19
  • 33
1

You could use C's overload mechanism:

void set_signal_action(int signal, void(*)(int))
{
    // install signal action
}
void set_signal_handler(int signal, void(*)(int, siginfo_t*, void*))
{
    // install signal handler
}

#define setSignalHandler(signal, X) _Generic                \
    (                                                       \
        (X),                                                \
        void(*)(int):                    set_signal_action, \
        void(*)(int, siginfo_t*, void*): set_signal_handler \
    )(signal, X)

This way you could use the same handler for any of the two types, though you would have to install it immediately:

if (some_condition)
{
    setSignalHandler(s, my_action);
}
else if(some_other_condition)
{
    setSignalHandler(s, SIG_IGN);
}
else
{
    setSignalHandler(s, SIG_DFL);
}

To actually install the signal handler at a later point of time you might modify the setter functions above to accept instead of the signal (int) a struct sigaction* parameter such that the appropriate member is set and the flags are adjusted accordingly without already installing the handler (leaving this to you...).

Aconcagua
  • 24,880
  • 4
  • 34
  • 59