int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
中的
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sa_flags 各参数作用
1.SA_NODEFER 作用:
Do not prevent the signal from being received from within its own signal handler. This flag is only meaningful when establishing a signal handler.
SA_NOMASK is an obsolete, non-standard synonym for this flag.
个人理解:设置了该参数,就是允许 当前正在处理 该信号的 信号函数中,可以继续接受并处理该信号。
示例参见 :
-
#include<stdio.h>
-
#include<signal.h>
-
-
void handler(int signo)
-
{
-
printf("Into handler\n");
-
while(1);
-
}
-
int main()
-
{
-
struct sigaction act;
-
act.sa_handler = handler;
-
act.sa_flags = 0;
-
sigemptyset(& act.sa_mask);
-
sigaction(SIGINT, &act, NULL);
-
while(1);
-
return 0;
-
}
如上代码:13行中sa_flags啥标记都没设置
[root@localhost c]# gcc signal_SA_NODEFER.c
[root@localhost c]# ./a.out
^CInto handler
^C^C^C^C^C^C
注意只有第一次按CTRL+C 时,打印了Into handler,而之后的怎么按ctrl+C都没反应
而该信号函数正在执行while(1); 就忽略了新收到的信号。
如下设置
act.sa_flags |= SA_NODEFER;
之后的行为,则可以在处理信号函数的过程中继续接受并处理该信号,可以看到每按一次CTRL+C就可以print 一次Into handler
-
[root@localhost c]# cat signal_SA_NODEFER.c
-
#include<stdio.h>
-
#include<signal.h>
-
-
void handler(int signo)
-
{
-
printf("Into handler\n");
-
while(1);
-
}
-
int main()
-
{
-
struct sigaction act;
-
act.sa_handler = handler;
-
act.sa_flags |= SA_NODEFER;
-
sigemptyset(& act.sa_mask);
-
sigaction(SIGINT, &act, NULL);
-
while(1);
-
return 0;
-
}
-
[root@localhost c]# gcc signal_SA_NODEFER.c
-
[root@localhost c]# ./a.out
-
^CInto handler
-
^CInto handler
-
^CInto handler
-
^CInto handler
当然:一般信号函数中仅仅设置一个flag,然后直接返回,而在程序的主loop中去处理这个flag对于的操作
如:
-
#include<stdio.h>
-
#include<signal.h>
-
-
static volatile do_print = 0;
-
-
void handler(int signo)
-
{
-
do_print = 1;
-
}
-
int main()
-
{
-
struct sigaction act;
-
act.sa_handler = handler;
-
act.sa_flags = 0;
-
sigemptyset(&act.sa_mask);
-
sigaction(SIGINT, &act, NULL);
-
while(1)
-
{
-
if (do_print)
-
{
-
printf("Into handler\n");
-
do_print = 0;
-
}
-
}
-
return 0;
-
}
执行结果:
[root@localhost c]# ./a.out
^CInto handler
^CInto handler
^CInto handler
可以看到 这样即使不设置act.sa_flags |= SA_NODEFER 也可以得到期望的结果,
为啥呢?
主要还是 该信号处理函数非常简单,程序在收到下一次的ctrl+c信号时,上个已经执行完毕了,所以不加也没关系,
但如果信号函数中要处理一系列的流程,最好还是加上,比如 服务器程序在收到SIGSEGV,或SIGBUS 等异常时,程序需要在信函函数中将异常的堆栈信息dump到日志中时,最好还是加上,这样可以尽可能多的将堆栈dump出来用来查错,这部分可以参照squid中对信号的处理。
另外:为啥信号函数中一般只是设置个flag 就返回呢?
这里面常见的一个故障就是:信号的到来是不确定的,而好多函数是可以被信号打断的,
比如在当前程序 正在调用malloc 分配一片内存(还尚未执行完),突然来了个信号被打断了,去执行信号函数了,而信号函数中又去调用了一次malloc,完了,死锁了。。
如:
[root@localhost ]# gstack 9277
#0 0x0000003cbd8f0dfe in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x0000003cbd87c1e8 in _L_lock_9162 () from /lib64/libc.so.6
#2 0x0000003cbd879ae2 in malloc () from /lib64/libc.so.6
#3 0x0000003cbd87fe62 in strndup () from /lib64/libc.so.6
#4 0x0000000000406ee4 in str_strs(char*, char, char***) ()
#5 0x0000000000404100 in sigcatcher(int, int, sigcontext*) ()
#6
#7 0x0000003cbd875812 in malloc_consolidate () from /lib64/libc.so.6
#8 0x0000003cbd8786c2 in _int_malloc () from /lib64/libc.so.6
#9 0x0000003cbd87aab6 in _int_realloc () from /lib64/libc.so.6
#10 0x0000003cbd87ad65 in realloc () from /lib64/libc.so.6
#11 0x00000000004043d6 in main ()
main中第10行正在realloc 在第6行中被打断,然后在信号处理函数中 又执行了一次 malloc,出现了死锁。(此处怀疑应该是malloc分配时必然存在一个全局的锁)
这部分apue信号处理的章节有详述。
阅读(4316) | 评论(3) | 转发(2) |