首页 文章

fork(应该是)在线程程序中对信号处理程序是否安全?

提问于
浏览
21

我真的不确定POSIX在存在线程和信号时对 fork 的安全性的要求 . fork 被列为异步信号安全函数之一,但如果库代码有可能注册了非同步信号安全的 pthread_atfork 处理程序,这是否会否定 fork 的安全性?答案取决于运行信号处理程序的线程是否正在使用atfork处理程序所需的资源?或者换句话说,如果atfork处理程序使用同步资源(互斥体等),但是从一个永远不会访问这些资源的线程中执行的信号处理程序调用 fork ,程序是否符合要求?

在这个问题的基础上,如果"thread-safe" forking在系统库内部使用 pthread_atfork 建议的习语实现(获取prefork处理程序中的所有锁并释放父和子postfork处理程序中的所有锁),那么 fork 可以安全使用来自线程程序中的信号处理程序?处理信号的线程是否可能在调用 mallocfopen / fclose 并持有全局锁定的过程中,导致 fork 期间出现死锁?

最后,即使 fork 在信号处理程序中是安全的,信号处理程序中的 fork 是安全的,然后从信号处理程序返回,或者在信号处理程序中调用 fork 总是需要后续调用 _exit 或其中一个 exec 信号处理程序返回之前的函数族?

5 回答

  • 2

    尽力回答所有子问题;我很抱歉,其中一些比理想应该更为模糊:

    如果库代码有可能注册了非异步信号安全的pthread_atfork处理程序,这会否定fork的安全性吗?

    是 . fork documentation明确提到:

    When the application calls fork() from a signal handler and any of the
       fork handlers registered by pthread_atfork() calls a function that is
       not asynch-signal-safe, the behavior is undefined.
    

    当然,这意味着您实际上不能将 pthread_atfork() 用于使多线程库对于认为它们是单线程的进程透明的目的,因为没有任何pthread同步函数是异步信号安全的 . 这被指出为规范中的缺陷,请参阅http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt(搜索"L16723") .

    答案取决于运行信号处理程序的线程是否可以使用atfork处理程序所需的资源?或者换句话说,如果atfork处理程序使用同步资源(互斥体等),但是从一个永远不会访问这些资源的线程中执行的信号处理程序调用fork,程序是否符合要求?

    严格来说答案是否定的,因为根据规范,功能要么是异步信号安全的,要么是不是;没有“在某些情况下安全”的概念 . 在实践中,你可能会侥幸逃脱,但是你很容易受到一种笨重但正确的实现的影响,而这种实现并没有按照你期望的方式划分资源 .

    在这个问题的基础上,如果使用pthread_atfork建议的习语在系统库内部实现“线程安全”分叉(获取prefork处理程序中的所有锁并释放父和子postfork处理程序中的所有锁),那么fork在线程程序中是否可以安全地使用信号处理程序?处理信号的线程是否可能在调用malloc或fopen / fclose并持有全局锁的过程中,导致fork期间出现死锁?

    如果以这种方式实现,那么你是对的,来自信号处理程序的 fork() 永远不会是安全的,因为如果调用线程已经持有它,尝试获取锁可能会死锁 . 但这意味着使用这种方法的实现不符合要求 .

    以glibc为例,它没有那样做 - 相反,它需要两种方法:首先,它获得的锁是递归的(所以如果当前线程已经有它们,它们的锁定数将会增加);此外,在子进程中,它只是单方面覆盖所有锁 - 请参阅 nptl/sysdeps/unix/sysv/linux/fork.c 中的这个摘录:

    /* Reset the file list.  These are recursive mutexes.  */
      fresetlockfiles ();
    
      /* Reset locks in the I/O code.  */
      _IO_list_resetlock ();
    
      /* Reset the lock the dynamic loader uses to protect its data.  */
      __rtld_lock_initialize (GL(dl_load_lock));
    

    其中每个 resetlocklock_initialize 函数最终调用glibc的内部等价物 pthread_mutex_init() ,无论是否有任何服务员,都会有效地重置互斥锁 .

    我认为理论是,通过获得(递归)锁,它保证没有其他线程会触及数据结构(至少以可能导致崩溃的方式),然后重置单个锁确保资源不是'永久封锁(重置当前线程的锁是安全的,因为现在没有其他线程可以争用数据结构,并且实际上直到使用锁的任何函数都没有返回) .

    我'm not 100% convinced that this covers all eventualities (not least because if/when the signal handler returns, the function that'只是把它的锁被盗将尝试解锁它和内部递归解锁函数不能防止解锁太多次!) - 但似乎可以在异步信号安全递归锁之上构建一个可行的方案 .

    最后,即使fork在信号处理程序中是安全的,在信号处理程序中分叉然后从信号处理程序返回是安全的,或者在信号处理程序中调用fork也总是需要后续调用_exit或其中一个exec系列函数在信号处理程序返回之前?

    我假设你在谈论孩子的过程? (如果 fork() 是异步信号安全意味着什么,那么应该可以在父母中返回!)

    没有在规范中发现任何其他情况(虽然我可能已经错过了)我认为它应该是安全的 - 至少,'safe'在某种意义上说,从孩子的信号处理程序返回并不意味着未定义的行为本身,虽然多线程进程刚刚分叉的事实可能意味着 exec*()_exit() 可能是最安全的行动方案 .

  • 0

    我正在添加这个答案,因为看起来 fork() 可能不再被视为异步安全 . 至少这似乎是 glibc 的情况,但POSIX中可能不再存在支持 . 目前标记为"accepted"的答案似乎得出结论认为它是安全的,但至少在 glibc 中可能并非如此 .

    在这个问题的基础上,如果使用pthread_atfork建议的习语在系统库内部实现“线程安全”分叉(获取prefork处理程序中的所有锁并释放父和子postfork处理程序中的所有锁),那么fork在线程程序中是否可以安全地使用信号处理程序?处理信号的线程是否可能在调用malloc或fopen / fclose并持有全局锁的过程中,导致fork期间出现死锁?

    确实!从this very reason列表中看起来好像是The Open Group resolved to remove it .

    IEEE 1003.1c-1995解释请求#37关于 pthread_atfork .

    解释委员会认为......以下解释性补充:Pg 78第864行“此外,pthread_atfork从信号处理程序调用的分支中设置的fork处理程序的调用需要是异步安全的 . ”

    glibc Bug 4737标识_664503_从异步安全函数列表中逐出的分辨率, posix_spawn() 用于填充其位置 . 不幸的是,它被解决为 WONTFIX 所以甚至连更新的联机帮助页都没有 .

  • 0

    在信号处理程序中使用fork()应该没问题 .

    pthread_atfork听起来像个坏主意 .

    为了回答你原来的问题,pthread不能保证调用任何pthread_atfork函数的安全是异步信号安全的,因为内核的信号实现使得这是不可能的 .

    哦,如果你在信号处理程序中分叉,不要让子进程从信号处理程序返回 . 这是未定义的 .

  • 12

    据我所知,fork source in glibc它使用信号状态临界区来确保分叉过程不会被信号中断 .

    ss = _hurd_self_sigstate ();
      __spin_lock (&ss->critical_section_lock);
    

    由于 pthread_atfork 处理程序在关键部分锁定后执行 - 它们自动变为信号安全 .

    可能是我错了,我会很感激修正 .

  • 4

    这里https://www.securecoding.cert.org/confluence/display/seccode/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers

    fork被列为异步信号安全,因此可以使用它 .

    POSIX Open Group Base Specifications [Open Group 2004]中的下表定义了一组异步信号安全的函数 . 应用程序可以无限制地从信号处理程序调用这些函数 . 异步信号安全函数fork()

相关问题