linux 捕获信号处理中遇到的死锁
tag: 信号 signal sigchld 死锁 堆栈
我们的程序需要捕获信号自己处理,所以尝试对1-32的信号处理(后面33-64的信号不处理)。
但是在调试代码时,发现一个线程死锁的问题。
程序目的:捕获信号,然后打印堆栈。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
伪代码如下:设置捕获信号函数(){ //设置信号处理函数 sigact.sa_sigaction = TsSigHandler; // //这里捕获了很多信号,包括SIGCHLD:子进程结束,父进程会收到该信号 sigaction( SIGSEGV, &sigact, NULL ); .... sigaction( SIGCHLD, &sigact, NULL ); } 信号处理函数:TsSigHandler{ //调用打印堆栈函数 PrintStack();} 打印堆栈函数PrintStack{ //打印堆栈 backtrace(); backtrace_symbols(); //调用system函数执行一些命令 system("xxxxxx");} |
Thread 12 (Thread 0xf7dd2b90 (LWP 5770)):
以下是一个让我觉得奇怪的堆栈,奇怪之处:
1.死锁了:__lll_lock_wait_private
2.获得了2个信号:<signal handler called>,为什么不是一个一个信号处理
堆栈如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#0 0xffffe410 in __kernel_vsyscall ()#1 0x002a0783 in __lll_lock_wait_private () from /lib/libc.so.6#2 0x001f8448 in _L_lock_124 () from /lib/libc.so.6#3 0x001f7f8b in do_system () from /lib/libc.so.6#4 0x001f8412 in system () from /lib/libc.so.6#5 0x00317ead in system () from /lib/libpthread.so.0#6 0x080f95c1 in PrintStack() ()#7 0x080f9844 in TsSigHandler(int, siginfo*, void*) ()#8 <signal handler called>#9 0xffffe410 in __kernel_vsyscall ()#10 0x001eb1a9 in sigprocmask () from /lib/libc.so.6#11 0x001f8132 in do_system () from /lib/libc.so.6#12 0x001f8412 in system () from /lib/libc.so.6#13 0x00317ead in system () from /lib/libpthread.so.0#14 0x080f95c1 in PrintStack() ()#15 0x080f9844 in TsSigHandler(int, siginfo*, void*) ()#16 <signal handler called>#17 0x002338ec in memcpy () from /lib/libc.so.6#18 0x0804fa02 in boom ()#19 0x080dbd9c in RunCmd ()#20 0x080dbf12 in CmdParse ()#21 0x080dc705 in OspTeleDaemon ()#22 0x080f8817 in OspTaskTemplateFunc(void*) ()#23 0x0030f832 in start_thread () from /lib/libpthread.so.0#24 0x00293e0e in clone () from /lib/libc.so.6 |
#18 0x0804fa02 in boom ()
boom()是我写的一个制造崩溃的函数:
char *pBoom = NULL;
memcpy( pBoom, "aaaa", 100 );
#16 <signal handler called>
触发信号
#15 0x080f9844 in TsSigHandler(int, siginfo*, void*) ()
TsSigHandler是信号处理函数。通过以下代码设置:
struct sigaction sigact;
sigemptyset( &sigact.sa_mask );
sigact.sa_flags = SA_ONESHOT | SA_SIGINFO;
sigact.sa_sigaction = TsSigHandler;
信号触发后,由TsSigHandler函数处理
#14 0x080f95c1 in PrintStack() ()
TsSigHandler函数中调用PrintStack函数打印堆栈。
#13 0x00317ead in system () from /lib/libpthread.so.0
PrintStack函数中调用了system函数做一些额外的事情,例如执行gcore(事实证明,这种方法是有点问题的)。
#11 0x001f8132 in do_system () from /lib/libc.so.6
system调用了do_system
#10 0x001eb1a9 in sigprocmask () from /lib/libc.so.6
do_system调用sigprocmask
#8 <signal handler called>
关键来了:这是获取到了另外一个信号:SIGCHLD。
#7 0x080f9844 in TsSigHandler(int, siginfo*, void*) ()
又调用信号处理函数TsSigHandler
#3 0x001f7f8b in do_system () from /lib/libc.so.6
system调用do_system,调用流程和上面当然是一样的
#2 0x001f8448 in _L_lock_124 () from /lib/libc.so.6
#1 0x002a0783 in __lll_lock_wait_private () from /lib/libc.so.6
nice!锁住了。。
分析:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
/* Execute LINE as a shell command, returning its status. */static intdo_system (const char *line){ int status, save; pid_t pid; struct sigaction sa;#ifndef _LIBC_REENTRANT struct sigaction intr, quit;#endif sigset_t omask; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; __sigemptyset (&sa.sa_mask); DO_LOCK (); if (ADD_REF () == 0) { if (__sigaction (SIGINT, &sa, &intr) < 0) { (void) SUB_REF (); goto out; } if (__sigaction (SIGQUIT, &sa, &quit) < 0) { save = errno; (void) SUB_REF (); goto out_restore_sigint; } } DO_UNLOCK (); /* We reuse the bitmap in the 'sa' structure. */ __sigaddset (&sa.sa_mask, SIGCHLD); save = errno; if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) {#ifndef _LIBC if (errno == ENOSYS) __set_errno (save); else#endif { DO_LOCK (); if (SUB_REF () == 0) { save = errno; (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); out_restore_sigint: (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); __set_errno (save); } out: DO_UNLOCK (); return -1; } }#ifdef CLEANUP_HANDLER CLEANUP_HANDLER;#endif#ifdef FORK pid = FORK ();#else pid = __fork ();#endif if (pid == (pid_t) 0) { /* Child side. */ const char *new_argv[4]; new_argv[0] = SHELL_NAME; new_argv[1] = "-c"; new_argv[2] = line; new_argv[3] = NULL; /* Restore the signals. */ (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); INIT_LOCK (); /* Exec the shell. */ (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); _exit (127); } else if (pid < (pid_t) 0) /* The fork failed. */ status = -1; else /* Parent side. */ { /* Note the system() is a cancellation point. But since we call waitpid() which itself is a cancellation point we do not have to do anything here. */ if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) status = -1; }#ifdef CLEANUP_HANDLER CLEANUP_RESET;#endif save = errno; DO_LOCK (); if ((SUB_REF () == 0 && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) {#ifndef _LIBC /* glibc cannot be used on systems without waitpid. */ if (errno == ENOSYS) __set_errno (save); else#endif status = -1; } DO_UNLOCK (); return status;} |
system()函数执行的大体过程是:fork()->exec()->waitpid(),
waitpid用于等待子进程执行完毕。
但是在子进程执行完毕时,会产生SIGCHLD信号,
而SIGCHLD信号会唤醒wait中的进程,这就是看到了2个信号的原因,
解决方法:
1.忽略SIGCHLD信号:其实这个信号一般情况下应该被忽略,除非你的程序需要对这种情况做非常特殊的处理
2.不要在这里调用system()
to do: 有空了记得补详细些
linux 捕获信号处理中遇到的死锁的更多相关文章
- Linux 多线程应用中如何编写安全的信号处理函数
http://blog.163.com/he_junwei/blog/static/1979376462014021105242552/ http://www.ibm.com/developerwor ...
- Linux 多线程应用中如何编写安全的信号处理函数【转】
转自:https://www.cnblogs.com/virusolf/p/4945642.html http://blog.163.com/he_junwei/blog/static/1979376 ...
- (4.7)怎么捕获和记录SQL Server中发生的死锁?
转自:https://blog.csdn.net/c_enhui/article/details/19498327 怎么捕获和记录SQL Server中发生的死锁? 关键词:死锁记录,死锁捕获 sql ...
- linux 多线程信号处理总结
linux 多线程信号总结(一) 1. 在多线程环境下,产生的信号是传递给整个进程的,一般而言,所有线程都有机会收到这个信号,进程在收到信号的的线程上下文执行信号处理函数,具体是哪个线程执行的难以获知 ...
- Linux驱动设备中的并发控制
一.基本概念 二.中断屏蔽 三.原子操作 四.自旋锁 五.信号量 六.互斥体 七.自旋锁与信号量的比较 Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态,即使 ...
- 基于innodb_print_all_deadlocks从errorlog中解析MySQL死锁日志
本文是说明如何获取死锁日志记录的,不是说明如何解决死锁问题的. MySQL的死锁可以通过show engine innodb status;来查看,但是show engine innodb statu ...
- JDK中ThreadDump诊断Java代码中的线程死锁问题
多线程的死锁..死锁不是死了而是线程互相等待... 在项目中可能就是在几十万行的代码中存在一个死锁的问题,如何发现这个问题并且解决这个问题. JavaJDK为我们提供了一个诊断工具叫做ThreadDu ...
- Linux内核调试方法总结之死锁问题分析
死锁问题分析 死锁就是多个进程(线程)因为等待别的进程已占有的自己所需要的资源而陷入阻塞的一种状态,死锁状态一旦形成,进程本身是解决不了的,需要外在的推动,才能解决,最重要的是死锁不仅仅影响进程业务, ...
- 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)
作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...
随机推荐
- BZOJ1029 建筑抢修
Description 小刚在玩JSOI提供的一个称之为"建筑抢修"的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重 ...
- js日期的写法,获取girdviw的行数、提示信息、验证数量信息
//制订日期(js日期的写法) var myDate = new Date(); var theDate = myDate.toLocaleDateString(); //获取今天的日期 //获取控 ...
- [JFinal 2] JFinal 开发框架
导读:在这次和大家一起开发的今日开讲后台管理系统中,我们用的是JFinal框架.开始的时候,说是用SSH,心里一阵窃喜,刚刚做了网上商城的项目,对于这个框架还算是接触过了.JFinal却是个新货,心里 ...
- SQL server 时间处理自连接
--延时的订单select t1.OrderId order1, t1.VerifyStatusId id1,t1.VerifyDate '时间1', t2.OrderId order2, t2.V ...
- 著名的二分查找的BUG
int binarySearch(int a[], int key, int length) { int low = 0; int high = length - 1; while (low < ...
- 用AsyncTask 来实现下载图片在android开发中
Android使用AsyncTask 有如下好处: 1. 线程的开销较大,如果每个任务都要创建一个线程,那么应用程序的效率要低很多: 2. 线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有 ...
- jQuery插件Skippr实现焦点图
史上效果最好的焦点图幻灯片jQuery插件Skippr,轻量级插件.响应式布局插件,强大的参数自定义 配置,可自定义切换速度.切换方式.是否显示左右箭头.是否自动播放.自动播放间隔时间等配置 参数,调 ...
- 软件工程 speedsnail 第二次冲刺5
20150522 完成任务:蜗牛帧数变化已经实现,行走的蜗牛具有了动态的视觉效果: 遇到问题: 问题1 帧数大小根据人眼来设置 解决1 除29余0到14的为第一帧 明日任务: 蜗牛碰撞身体翻转
- Custom Sort Order
When trying to sort based on values that do not fit the standard ascending and descending sort logic ...
- 封装js千分位加逗号和删除逗号
//封装js千分位加逗号和删除逗号 alert( format(2545678754.020001) ) //2,545,678,754.03 alert( format(-2545678754.02 ...