将自定义函数设置为所有信号的处理程序

Tom*_*scu 6 c unix signals

我有这个任务要做:

编写一个函数void myfunct(void(*f)(int sig)),将其设置f为所有可能信号的处理程序。

我有两个问题:

  1. 如何获得所有可能的信号?有这个功能吗?我可以以某种方式迭代它们吗?
  2. f考虑到它需要一个参数,将函数设置为处理程序真的会起作用吗?不是应该没有任何参数吗?

谢谢。

Nom*_*mal 5

我个人会迭代信号编号的静态列表,并使用预处理器指令来检测支持哪些信号(在编译时)。例如:

#include <signal.h>

static const all_signals[] = {
#ifdef SIGHUP
    SIGHUP,  /* POSIX.1 */
#endif
#ifdef SIGQUIT
    SIGQUIT, /* POSIX.1 */
#endif
#ifdef SIGTRAP
    SIGTRAP, /* POSIX.1 */
#endif
#ifdef SIGIO
    SIGIO,   /* BSD/Linux */
#endif

/*
 * Other signal names omitted for brevity
*/

/* C89/C99/C11 standard signals: */
    SIGABRT,
    SIGFPE,
    SIGILL,
    SIGINT,
    SIGSEGV,
/* SIGTERM (C89/C99/C11) is also the terminating signal number */
    SIGTERM
};
Run Code Online (Sandbox Code Playgroud)

SIGTERM安装信号处理程序的数组中的最后一个条目:

    struct sigaction  act;
    int               i = 0;

    memset(&act, 0, sizeof act);
    sigemptyset(&act.sa_mask);
    act.sa_handler = your_signal_handler;
    act.sa_flags = 0;

    do {
        if (sigaction(all_signals[i], &act, NULL)) {
            fprintf(stderr, "Cannot install signal %d handler: %s.\n", all_signals[i], strerror(errno));
            exit(EXIT_FAILURE);
        }
    } while (all_signals[i++] != SIGTERM);
Run Code Online (Sandbox Code Playgroud)

这样,您的代码不需要 POSIX 等支持即可工作,但如果在编译时可用,则支持 POSIX 信号。

您可以查看 Wikipedia Unix signal文章和man 7 signal来了解已知的信号名称。

您还可以使用以下命令安装 POSIX 实时信号的信号处理程序

#if SIGRTMAX-0 > SIGRTMIN-0
    for (i = SIGRTMIN; i <= SIGRTMAX; i++)
        if (sigaction(i, &act, NULL)) {
            fprintf(stderr, "Cannot install realtime signal %d handler: %s.\n", i, strerror(errno));
            exit(EXIT_FAILURE);
        }
#endif
Run Code Online (Sandbox Code Playgroud)


P.P*_*.P. 2

  1. 如何获得所有可能的信号?有这个功能吗?我可以以某种方式迭代它们吗?

大多数实现都提供一个常量,例如NSIGGlibc 提供NSIG)或_NSIGLinux 提供 _NSIG)。因此,您可以循环该常量并为所有常量设置相同的信号处理函数。

POSIX 没有定义“最高信号编号”的值。POSIX 中有一项建议添加宏NSIG_MAX

{NSIG_MAX}

sysconf(_SC_NSIG) 的最大可能返回值。请参阅[XSH sysconf() 的交叉引用]。{NSIG_MAX} 的值不应大于 sigset_t 类型(参见 [交叉引用])能够表示的信号数量,忽略 sigfillset() 或 sigaddset() 施加的任何限制。

但它还没有进入 POSIX(很可能它会成为 POSIX 版本的一部分 - 第 8 期)。

  1. 考虑到它需要一个参数,将函数 f 设置为处理程序真的会起作用吗?不是应该没有任何参数吗?

当您设置信号配置时,信号处理函数采用的参数并不重要。它需要信号号,但这并不妨碍您将其用作多个信号的处理程序。

但有些特殊情况你需要处理。某些无法捕获或忽略的信号(SIGKILLSIGSTOP)。还有其他信号(SIGFPESIGILLSIGSEGV),虽然允许捕获,但信号处理程序无法返回到其调用者(即您需要从信号处理程序退出)。