我遇到了一个非常讨厌的问题: 我有一个程序在开始时创建一个线程,这个线程将在执行期间启动其他东西(fork()immediatly后跟execve())。
这是我的程序到达(我认为)死锁的两个线程的bt:
线程2(LWP 8839):
#0 0x00007ffff6cdf736在__libc_fork()中.. / sysdeps / nptl / fork.c:125
_IO_new_proc_open中的#1 0x00007ffff6c8f8c0(fp = fp @ entry = 0x7ffff00031d0,command = command @ entry = 0x7ffff6c26e20“ps -u brejon | grep \”cvc \“
#2 0x00007ffff6c8fbcc in _IO_new_popen(command = 0x7ffff6c26e20“ps -u user
| grep \”cvc \“| wc -l”,mode = 0x42c7fd“r”)at iopopen.c:296
#3-4 ......
#5 0x00007ffff74d9434 in start_thread(arg = 0x7ffff6c27700)at pthread_create.c:333
克隆()中的#6 0x00007ffff6d0fcfd在../sysdeps/unix/sysv/linux/x86_64/clim.S:109
线程1(LWP 8835):
#0 __lll_lock_wait_private()at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
#1 0x00007ffff6ca0ad9 in malloc_atfork(sz = 140737337120848,caller =)at arena.c:179
文件门户网站__GI__IO_file_doallocate(fp = 0x17a72230)中的#2 0x00007ffff6c8d875:127
#3 0x00007ffff6c9a964 in __GI__IO_doallocbuf(fp = fp @ entry = 0x17a72230)at genops.c:398
#4 0x00007ffff6c99de8 in _IO_new_file_overflow(f = 0x17a72230,ch = -1)at fileops.c:820
#5 0x00007ffff6c98f8a in _IO_new_file_xsputn(f = 0x17a72230,data = 0x17a16420,n = 682)at fileops.c:1331
#6 0x00007ffff6c6fcb2 in _IO_vfprintf_internal(s = 0x17a72230,format =,ap = ap @ entry = 0x7fffffffcf18)at vfprintf.c:1632
#7 0x00007ffff6c76a97 in __fprintf(stream =,format =)at fprintf.c:32
#8-11 ......
在主电源中的#12> 0x000000000042706e(argc = 3,argv = 0x7fffffffd698,envp = 0x7fffffffd6b8)电源/忽略/ .c:146两者都坚持使用glibc-2.17和glibc-2.23
欢迎任何帮助:'D
编辑:
这是一个最小的例子:
1 #include <stdlib.h>
2 #include <pthread.h>
3 #include <unistd.h>
4
5 void * thread_handler(void * args)
6 {
7 char * argv[] = { "/usr/bin/ls" };
8 char * newargv[] = { "/usr/bin/ls", NULL };
9 char * newenviron[] = { NULL };
10 while (1) {
11 if (vfork() == 0) {
12 execve(argv[0], newargv, newenviron);
13 }
14 }
15
16 return 0;
17 }
18
19 int main(void)
20 {
21 pthread_t thread;
22 pthread_create(&thread, NULL, thread_handler, NULL);
23
24 int * dummy_alloc;
25
26 while (1) {
27 dummy_alloc = malloc(sizeof(int));
28 free(dummy_alloc);
29 }
30
31 return 0;
32 }
环境: user:deadlock $ cat / etc / redhat-release
Scientific Linux版本7.3(氮气)
user:deadlock $ ldd --version
ldd(GNU libc)2.17
编辑2: rpm软件包版本为:glibc-2.17-196.el7.x86_64
我无法使用rpm包获取行号。这是BT使用glibc给出的分布:用debuginfo解决。
(gdb)线程应用所有bt
线程2(线程0x7ffff77fb700(LWP 59753)):
#0 vfork()at ../sysdeps/unix/sysv/linux/x86_64/vfork.S:44
在deadlock.c:11 中的thread_handler(args = 0x0)中的#1 0x000000000040074e
#2 0x00007ffff7bc6e25 in start_thread(arg = 0x7ffff77fb700)at pthread_create.c:308
克隆()中的#3 0x00007ffff78f434d在../sysdeps/unix/sysv/linux/x86_64/clim.S:113
线程1(线程0x7ffff7fba740(LWP 59746)):
#0 0x00007ffff7878226 in _int_free(av = 0x7ffff7bb8760,p = 0x602240,have_lock = 0)at malloc.c:3927
#1 0x00000000004007aa in main()at deadlock.c:28
答案 0 :(得分:3)
这是一个自定义编译的glibc。安装可能出现问题。请注意Red Hat Enterprise Linux 7.4 backports a fix for a deadlock between malloc and fork,你错过了,因为你编译了自己的glibc。 fix for the upstream bug仅进入上游版本2.24,因此如果您将自定义构建基于此,则可能没有此修复程序。 (虽然回溯对于那个回溯看起来会有所不同。)
我认为我们修复了至少另一个2.17后与libio相关的死锁错误。
编辑我一直处理与fork相关的死锁已经太久了。发布的重现器存在多个问题:
waitpid
调用PID。因此,流程表将很快被僵尸填满。execve
的错误检查。如果/usr/bin/ls
路径名不存在(例如,在未经历UsrMove的系统上),则execve
将返回,并且循环的下一次迭代将启动另一个 vfork
致电。我修复了两个问题(因为调试接近一个分叉炸弹的东西根本不好玩),但是我无法用glibc-2.17-196.el7.x86_64重现一个挂起。