【问题标题】:How to leave (interrupt) the waitpid() function?如何离开(中断)waitpid()函数?
【发布时间】:2018-10-29 18:02:06
【问题描述】:

目前我正在编写一个 shell,并为我的子进程使用 waitpid() 函数。

我还安装了一个信号处理程序,因此我可以捕获 SIGINT (CTRL+C) 信号。

所以我现在想要的是当有人按下 SIGINT (CTRL+C) 信号时,它应该离开 waitpid() 函数并像往常一样继续运行。

我正在寻找一个可以帮助我的函数。

【问题讨论】:

  • 拨打sigaction()时不要在标志中设置SA_RESTART。
  • ...sigaction() 比使用signal() 安装信号处理程序更受欢迎。
  • 考虑同时处理SIGCHLD 信号,参见signal(7) & signal-safety(7)

标签: c shell unix wait waitpid


【解决方案1】:

在waitpid() 上阻塞的进程将在接收到信号时返回并将errno 设置为EINTR。

为此,我没有使用SA_RESTART 选项安装信号处理程序。

要安装信号句柄而不设置选项SA_RESTART,首选函数是sigaction()。

void handle(int sig)
{
  /* Do nothing. */
}

int main(void)
{
  sigaction(SIGINT, (struct sigaction){handler}, NULL);

  /* fork and bla ... */

  if (-1 == waitpid(..., /*no WNOHANG here */))
  {
    if (EINTR == errno)
    {
      /* process received signal */
      ...

【讨论】:

    【解决方案2】:

    安装您的信号处理程序没有 SA_RESTART 标志:

    void handler( int sig, siginfo_t *si, void *arg )
    {
        ...
    }
    
    ...
    
    struct sigaction newact;
    memset( &newact, 0, sizeof( newact ) );
    sigemptyset( &newact.sa_mask );
    newact.sa_flags = SA_SIGINFO;  // note that **lack** of SA_RESTART
    newact.sa_siginfo = handler;
    
    sigaction( SIGINT, &newact, NULL );
    

    您必须为此添加错误检查,并注意您现在必须处理代码中的中断调用。

    【讨论】:

    • OT:我会使用 struct sigaction newact = {0}; 而不是调用 memset()。
    • @alk 我已经存在太久了... :-)
    • 我也怀疑是否有必要明确清空sa_mask。另外^2为什么要为实际上什么都不做的处理程序设置SA_SIGINFO。所以假设void handler(int sig); 那么短版本可能是{ sigaction(SIGINT, (struct sigaction){handler}, NULL); } :-)
    • 谢谢你的帮助,但我不明白你在叫什么,你有参考或类似的东西吗?
    • @alk 我倾向于偏执于确保我的所有变量都正确初始化——一种针对我将要放入的错误的防御性编码措施(两种程序员:创建错误的人,和骗子)。至于SA_SIGINFO,我们不知道他OP的信号处理函数是做什么的,所以我提供了一个更复杂用法的例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 2017-05-05
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    相关资源
    最近更新 更多