Linux信号丢失问题分析
来源:互联网 发布:c语言怎么求素数的和 编辑:程序博客网 时间:2024/04/30 08:36
转载自http://hi.baidu.com/qiupingwu/item/f8ff6d3856c051b8633aff0c
1. 问题引入
我们想实现这样的一个功能:通过使用~SIGUSR1~信号实现对守护进程的重启。
我们编写了如下代码:
/*restart1.c*/
#include<signal.h>
#include<stdio.h>
static void sig_usr(int signo)
{
if (SIGUSR1 == signo)
{
printf("received SIGUSR1\n");
system("restart.sh");
}
else
{
printf("received signal%d\n", signo);
}
}
int main()
{
if (SIG_ERR == signal(SIGUSR1, sig_usr))
{
printf("can't catch SIGUSR1\n");
}
for (;;)
{
pause();
}
}
#!/bin/bash
# restart.sh
pkill -9 daemon
sleep 1
./daemon &
经测试,发现的问题是当~daemon~程序第一次启动时,使用~kill -USR1 <pid>~命令可以令其重启。但是对于此后重启的~daemon~进程再也接收不到~kill~发送的~USR1~信号。
2. 原因分析
先是怀疑是不是使用~signal~存在不可靠信号丢失问题,于是改为~sigaction~进行测试。
修改后的代码为:
/*restart2.c*/
#include<signal.h>
#include<stdio.h>
static void sig_usr(int signo)
{
if (SIGUSR1 == signo)
{
printf("received SIGUSR1\n");
system("restart.sh");
}
else
{
printf("received signal%d\n", signo);
}
}
int main()
{
struct sigaction action;
sigaction(SIGUSR1, NULL, &action);
action.sa_handler = sig_usr;
sigaction(SIGUSR1, &action, NULL);
for (;;)
{
pause();
}
}
测试结果表明,问题依旧。
开始怀疑会不会是前后创建的进程不属于相同用户(或者是用户组、TTY、父进程)所致,但是通过使用~ps -ajx~命令查看,发现这些属性是相同的。
在测试过程还发现一个现象就是~daemon~在上一次接收过的信号,在其重启后都不能接收;但还没接收过的信号,仍然可以正常接收。
在阅读~LINUX kernel~源码的时候,发现~LINUX~在派生进程时,存在继承父进程信号屏蔽标识的现象。于是怀疑是不是由于子~daemon~进程不断继承父进程的屏蔽标识,致使用不能接收~USR1~信号?但是父进程又为何要屏蔽~USR1~信号呢?
查看~restart1.c~得知,我们在~sig\_usr~中执行~system~操作,从而派生了~daemon~进程。根据~LINUX~的信号 处理机制,我们知道为妨止在处理信号的过程中又来重复信号造成信号丢失,会采取屏蔽正在处理的信号标志位,以让重复信号排队;在处理完上一个信号后,再打 开标志位,接着处理重复信号。
于是在执行~sig\_usr~时,USR1~标志位是屏蔽的,而此时派生的进程该标志位估计也是屏蔽的(后面我们采用例子验证)。因此当~daemon~进程起来后,就不能接收~USR1~信号了。
一般~LINUX~编程建议,不要在中断中处理过于复杂的事情,因此首先简化~sig\_usr~进行测试。修改后的代码如下:
/*restart3.c*/
#include<signal.h>
#include<stdio.h>
static int resetflag = 0;
static void sig_usr(int signo)
{
if (SIGUSR1 == signo)
{
printf("received SIGUSR1\n");
resetflag = 1;
}
else
{
printf("received signal%d\n", signo);
}
}
int main()
{
if (SIG_ERR == signal(SIGUSR1, sig_usr))
{
printf("can't catch SIGUSR1\n");
}
for (;;)
{
pause();
if (1 == resetflag)
{
system("restart.sh");
exit(0);
}
}
}
测试通过。
再来验证一下重启的~daemon~子进程是否继承了父进程的屏蔽标志位,我们尝试强行清除子进程的~USR1~信号屏蔽标志位即可。
修改后的代码如下:
/*restart4.c*/
#include<signal.h>
#include<stdio.h>
static void sig_usr(int signo)
{
if (SIGUSR1 == signo)
{
printf("received SIGUSR1\n");
system("restart.sh");
}
else
{
printf("received signal%d\n", signo);
}
}
int main()
{
struct sigaction action;
sigset_t set;
sigaction(SIGUSR1, NULL, &action);
action.sa_handler = sig_usr;
sigaction(SIGUSR1, &action, NULL);
sigaddset(&set, SIGUSR1);
if (0 > sigprocmask(SIG_UNBLOCK, &set, NULL))
{
printf("sigprocmask error\n");
return 1;
}
for (;;)
{
pause();
}
}
测试仍然正常通过。
另外,还可以通过查看~/proc/<pid>/status~文件更直观地查看到指定进程的信息屏蔽情况。
+--------+-------------------------------+------------------+
| 段名 | 含义 | 例子 |
+--------+-------------------------------+------------------+
| SigPnd | The bitmap of pending signals | 0000000000000000|
| | (usually 0) | |
+--------+-------------------------------+------------------+
| SigBlk | The bitmap of blocked signals |0000000000000000|
| | (usually 0, 2 for shells) | |
+--------+-------------------------------+------------------+
| SigIgn | The bitmap of ignored signals |0000000000000027|
+--------+-------------------------------+------------------+
| SigCgt | The bitmap of catched signals | 0000000180000a00 |
+--------+-------------------------------+------------------+
3. 结论
1) 不要在中断函数中执行过于复杂的处理流程;
2) 在信号处理过程返回前,进程会对相同信号的标志进行屏蔽;
3) 父进程会把当前的信号屏蔽标志位信息传递给它派生的子进程。
- Linux信号丢失问题分析
- Linux c 信号丢失问题
- 信号丢失问题
- Linux信号机制分析
- Linux 信号机制分析
- Linux信号机制分析
- Linux信号机制分析
- linux 信号机制分析
- Linux 信号与信号处理分析
- linux 信号简单例子分析
- Linux信号(signal) 机制分析
- linux 信号列表及分析
- Linux信号(signal) 机制分析
- Linux信号(signal) 机制分析
- Linux信号(signal) 机制分析
- Linux信号(signal) 机制分析
- Linux信号(signal) 机制分析
- Linux信号(signal) 机制分析
- 11111 - Generalized Matrioshkas
- 定时器1的设置 s5pc100
- 给定一个函数rand5(),使函数rand7()可以随机等概率的生成1-7的整数
- cf 320B
- js与flash交互操作1
- Linux信号丢失问题分析
- jQuery.extend 函数详解
- ORACLE GOLDENGATE DML 双向同步
- Netjava Lesson8 多线程——让小球动起来
- 5个iOS应用开发者海外学习资源站推荐
- Android_自动化测试工具_Calabash(1)
- discuz/uchome等康盛产品formhash()浅析
- Java 用Look And Feel打造绚丽的界面外观!
- 使用OneNote来构建你自己的知识库