多线程+fork 引发的bug查找

1. 问题描述

    某个server SA是一个多线程服务器,主线程会调用fork,再exec生成工作进程SB。

    实际上,SA的主线程fork出了一个子线程,但没有执行exec。

# ps ajxf | grep r2server
14022 28342 28341 14022 pts/2    28341 S+       0   0:00  |       \_ grep r2server
    1 28046 28037  3823 ?           -1 Sl       0  31:25 ./r2server ../conf/r2server.conf
28046 28075 28037  3823 ?           -1 S        0   0:00  \_ ./r2server ../conf/r2server.conf

2. 问题定位

  2.1 用pstack观察2个进程当前stack状态。

# pstack 28075
#0  0x00007f40f24bf264 in __lll_lock_wait () from /lib64/libpthread.so.0
#1  0x00007f40f24ba508 in _L_lock_854 () from /lib64/libpthread.so.0
#2  0x00007f40f24ba3d7 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3  0x000000000043b407 in r2::log::LogFactory::log_printf(char const*, char const*, int, char const*, int, char const*, ...) ()

发现被lock住了。

google “pthread_mutex_lock owner”找到文献 https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks,

安装上面的方法,定位:

f 3

(gdb) info reg
rax            0xfffffffffffffe00       -512
rbx            0x7517a0 7673760
rcx            0xffffffffffffffff       -1
rdx            0x7f40d9ff86bf   139916512036543
rsi            0x80     128
rdi            0x753fb0 7684016
rbp            0x753fb0 0x753fb0
rsp            0x7f40d9ff85c0   0x7f40d9ff85c0
r8             0x753fb0 7684016

(gdb) p *(pthread_mutex_t*)0x753fb0
$1 = {__data = {__lock = 2, __count = 0, __owner = 28049,

说明当前线程的在等待一个锁,该锁被28049占有了。

# pstack 28049
Thread 1 (process 28049):
#0  0x00007f40f1a65ef3 in epoll_wait () from /lib64/libc.so.6

说明该线程已经释放了这个锁。

因此原因 是多线程+fork引起的bug:进程组28046里的主线程28046调用fork的时候,此时线程28049占用了一个锁A(正在打log),创建了子进程28075。

子进程执行exec前的代码,遇到log_printf调用,去申请锁A。因为锁A是被lock的,因此该进程死锁,执行不了到exec。

进程组28046的线程28049打完log后,释放了锁A(进程组28046和进程28075是两个不同的进程空间,有不同的page table。此时释放锁A会采用copy on write技术,创建一个新的锁A),继续正常执行。

根本原因:由于多线程的存在,某个线程占用了一个锁,因此fork的时候,fork出来的进程地址空间包含了这个被占用的锁。如果在exec之前,调用再申请这个锁,会导致死锁。

3. 解决方案

1. 多线程 or fork二选一。

2. 多线程+fork的时候,fork到exec之间只调用的async—signal function (man 7 singal),因为此时进程状态是unsafe的。

参考文献:

http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them

https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks

原文地址:https://www.cnblogs.com/Torstan/p/4915689.html