当前位置: 首页 > 面试题库 >

在Linux上显式调用SIG_DFL / SIG_IGN处理程序

姚高爽
2023-03-14
问题内容

我已阻止,然后通过以下代码等待信号:

sigset_t set;
sigfillset(&set); // all signals
sigprocmask(SIG_SETMASK, &set, NULL); // block all signals
siginfo_t info;
int signum = sigwaitinfo(&set, &info); // wait for next signal
struct sigaction act;
sigaction(signum, NULL, &act); // get the current handler for the signal
act.sa_handler(signum); // invoke it

由于处理程序设置为SIG_DFL(定义为0),最后一行生成分段错误。如果将默认处理程序设置为SIG_DFL或,该如何手动调用它SIG_IGN?另请注意,该SIG_IGN定义为1


问题答案:

当你发现你不能调用SIG_DFL和SIG_IGN 本身 。但是,您可以或多或少模仿它们的行为。

简而言之,模仿正常信号处理将是:

  • 用户定义的sa_handlers 很容易
  • 对于SIG_IGN来说足够简单,需要注意的是,对于CHLD,您需要waitpid()
  • 简单但对SIG_DFL却不愉快,因此重新提高了内核的魔力。

这是您想要的吗?

#include <signal.h>
#include <stdlib.h>

/* Manually dispose of a signal, mimicking the behavior of current
 * signal dispositions as best we can.  We won't cause EINTR, for
 * instance.
 *
 * FIXME:  save and restore errno around the SIG_DFL logic and
 *         SIG_IGN/CHLD logic.
 */
void dispatch_signal(const int signo) {
    int stop = 0;
    sigset_t oset;
    struct sigaction curact;

    sigaction(signo, NULL, &curact);

    /* SIG_IGN => noop or soak up child term/stop signals (for CHLD) */
    if (SIG_IGN == curact.sa_handler) {
        if (SIGCHLD == signo) {
          int status;
          while (waitpid(-1, &status, WNOHANG|WUNTRACED) > 0) {;}
        } 
        return;
    }

    /* user defined => invoke it */
    if (SIG_DFL != curact.sa_handler) {
        curact.sa_handler(signo);
        return;
    }

    /* SIG_DFL => let kernel handle it (mostly).
     *
     *  We handle noop signals ourselves -- "Ign" and "Cont", which we
     *  can never intercept while stopped.
     */
    if (SIGURG == signo || SIGWINCH == signo || SIGCONT == signo) return;

    /*  Unblock CONT if this is a "Stop" signal, so that we may later be
     *  woken up.
     */
    stop = (SIGTSTP == signo || SIGTTIN == signo || SIGTTOU == signo);
    if (stop) {
        sigset_t sig_cont;

        sigemptyset(&sig_cont);
        sigaddset(&sig_cont, SIGCONT);
        sigprocmask(SIG_UNBLOCK, &sig_cont, &oset);
    }

    /*  Re-raise, letting the kernel do the work:
     *     - Set exit codes and corefiles for "Term" and "Core"
     *     - Halt us and signal WUNTRACED'ing parents for "Stop"
     *     - Do the right thing if we forgot to handle any special
     *       signals or signals yet to be introduced
     */
    kill(getpid(), signo);

    /* Re-block CONT, if needed */
    if (stop) sigprocmask(SIG_SETMASK, &oset, NULL);
}

更新 (针对OP的精彩问题)

1:此插槽是否在sigwaitinfo之后?

是。就像是:

... block signals ...
signo = sigwaitinfo(&set, &info);
dispatch_signal(signo);

2:为什么不引发那些由SIG_IGN处理的信号,无论如何它们都会被忽略

与三个系统调用(重新引发,取消屏蔽,重新屏蔽)相比,在用户空间中进行noop效率更高。此外,当SIG_IGNored时,CHLD具有特殊的语义。

3:为什么要特别对待SIGCHLD?

最初(检查答案是否编辑)我没有-在SIG_IGN情况下重新提出,因为IGNored
CHLD信号告诉内核自动获得子级

但是,我进行了更改,因为“自然的”
CHLD信号携带有关终止过程的信息
(至少PID,状态和实际UID)。用户生成的CHLD信号不具有相同的语义,在我的测试中,对它们进行IGNoring不会导致2.6自动收起SIGCHLD被“遗漏”的排队的僵尸。所以,我自己做。

4:为什么与“停止”相关的信号会阻止CONT。 不会为CONT调用默认的处理程序吗?

如果我们停止(不执行)并且CONT被阻止,我们将永远不会收到唤醒我们的信号!

5:为什么不叫加注而不是加注的底线?

个人喜好; raise()也可以。



 类似资料:
  • 问题内容: 我试图了解Linux如何处理进程调度和线程调度。我读过Linux可以安排进程和线程。 Linux是否具有线程调度程序和进程调度程序?如果是,他们如何合作? 问题答案: 的Linux内核调度器被实际调度的任务,并且这些要么螺纹或(单线程)工艺。 因此,在调度程序的上下文中, 任务 (内核内部)是正在调度的事物,可以是某些 内核线程( 例如或),多线程进程的某些 用户线程 (例如)或单线程

  • 我有一个UITableView,在委托(视图控制器)中,我已经实现了该函数 然后,我测试编辑样式 作为删除的一部分,我请求用户确认,如果他们选择“是”,与该行相关的项目将被删除,如果他们选择“否”,我将重置编辑样式。 我似乎遇到的问题是没有调用任何完成处理程序。我在其他地方使用过这种格式,没有任何问题。 该警报将显示标题、消息以及按钮“取消”和“是”。如果我点击其中任何一个,什么都不会发生。警报被

  • 我试图使用一个简单的服务器-客户端应用程序(代码见下文)进入Netty。 我在与两个问题作斗争: null KJ 这就是服务器的创建方式: 其中一个处理程序类(FeedbackServerHandler执行完全相同的操作,但解析为整数):

  • 快速免责声明:我是一个。Net开发人员,可能没有提供您需要的有关环境的所有信息,但可以根据要求获取信息。我们有COBOL程序员,但他们从来没有这样做过。 我们正在将带有DB2数据库的大型机应用程序转换为。Net MVC应用程序和SQL数据库。我们希望从DB2上的COBOL存储过程调用一个大型机COBOL批处理程序。我读过这篇文章,但是我还没有找到一个好的例子来说明如何创建一个调用COBOL程序的C

  • 问题内容: 我正在学习React,并按照本教程创建了一个简单的Tic- Tac-Toe游戏,您可以在CodePen中查看。 对于在Board组件的函数内部返回的Square组件的属性中的箭头功能如何工作,我感到困惑。同样,我拥有的游戏组件也同样如此。我以为我可以不用箭头功能(就像一样)来编写它,但这会中断游戏。 问题答案: 期望功能。箭头函数没有自己的功能; 使用封闭执行上下文的值。箭头功能可替代

  • 我正在开发一个用PHP编写的预分叉TCP套接字服务器。 守护进程(父进程)分叉一定数量的子进程,然后等待,直到它被告知退出并且子进程都走了或者它收到信号。 SIGINT和SIGTERM使其将SIGTERM发送给所有子级。 孩子们建立了他们自己的信号处理器:SIGTERM导致一个干净的退出。SIGUSR1导致它转储一些状态信息(只需在下面的示例代码中打印出它收到了信号)。 如果子异常退出,则父级启动