中的
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.
个人理解:设置了该参数,就是允许 当前正在处理 该信号的 信号函数中,可以继续接受并处理该信号。
示例参见 :http://stackoverflow.com/questions/2418812/catching-signal-inside-its-own-handler
- #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
如:
- #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 ()
#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信号处理的章节有详述。