【问题标题】:Async signal safety of fork()fork() 的异步信号安全
【发布时间】:2017-05-13 18:28:02
【问题描述】:

根据 Oracle 的 Multithreaded Programming Guidefork() 应该可以在信号处理程序中安全使用。但是我的进程卡在了信号处理程序中,并跟随回溯:

 #0  __lll_lock_wait_private () at   ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
 #1  0x00007f86e6a9990d in _L_lock_48 () from /lib/x86_64-linux- gnu/libc.so.6
 #2  0x00007f86e6a922ec in ptmalloc_lock_all () at arena.c:242
 #3  0x00007f86e6ad5e82 in __libc_fork () at ./nptl/sysdeps/unix/sysv/linux/x86_64/../fork.c:95
 #4  0x00007f86e7d9f125 in __fork () at ./nptl/sysdeps/unix/sysv/linux/pt-fork.c:25
....
 #7  signal handler called

所以malloc 在信号处理程序中使用是不安全的,fork 可以是什么?

提前致谢。

【问题讨论】:

  • 问题可能不是fork,而是调用之后的你的代码。 (请注意,当信号处理程序损坏时,堆栈跟踪可能会产生误导。)
  • 给我们足够的代码来复制问题。最有可能的是,在准备该代码的过程中,您会发现问题——正是您删除的东西使问题消失了。
  • 您需要展示足够多的代码才能成为 MCVE (minimal reproducible example)。在跟踪中看到 malloc 令人担忧;这不一定是异步信号安全的。
  • 好吧,我找到了这个主题:sourceware.org/bugzilla/show_bug.cgi?id=4737#c23,他们对这个问题进行了长时间的讨论,但似乎没有解决:(
  • @Eyalleshem 绝对看起来像一个 glibc 错误。根据the latest POSIX standard:“虽然fork() 函数是异步信号安全的,但实现无法确定pthread_atfork() 建立的分叉处理程序是否是异步信号安全的。” glibc 应该使用非异步信号安全的分叉处理程序。这打破了fork()

标签: c linux fork solaris glibc


【解决方案1】:

现在是listed as a bug by RedHat

错误 1422161 - glibc:fork 不是异步信号安全的

...

+++ 这个错误最初是作为错误 #1422159 +++ 的克隆创建的

POSIX 要求 fork 是异步信号安全的。我们目前 实施不是。

【解决方案2】:

fork() 将通过复制父进程的一些内存来启动一个新进程,但两者都是独立的进程。所以在信号处理程序内部使用是安全的。下面是运行孩子的例子......

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

int SHOULD_RUN = 1;
void int_sig_handler(int signal){
        printf("SIG_INT\n");
        if(fork() == 0){
                // child code
                printf("I am Child");
                //signal(SIGINT, int_sig_handler);
                SHOULD_RUN = 1;
                while(SHOULD_RUN){
                        printf("I am Running Still...\n");
                        sleep(1);
                }
                exit(0);
        }else{
                // parent code
                printf("parent");
        }
        SHOULD_RUN = 0;
}


int main(int argc, const char *argv[]){
        signal(SIGINT, int_sig_handler);
        while(SHOULD_RUN){
                sleep(1);
        }
        return 0;
}

【讨论】:

  • 您必须了解您在运行时使用的实现,以及是否有任何限制符合 POSIX 标准要求的警告,即 fork() 是 AS 安全的。您不能仅仅假设它是安全的,您需要通过查看官方规范文档或阅读代码来验证它是否安全。在这种情况下,我们知道 glibc 的 fork 不是 AS 安全的,因为他们说它不是:sourceware.org/bugzilla/show_bug.cgi?id=19703
猜你喜欢
  • 2019-12-14
  • 2020-07-16
  • 1970-01-01
  • 2017-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多