我尝试使用sigaction安装信号处理程序,然后像这样在单个线程上调用它:
void
my_signal_handler ( int signo, siginfo_t *info, void *extra )
{
printf("my signal handler\n" );
}
int threadsupervisor() {
<...>
struct sigaction action;
struct sigaction oldHandler;
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = my_signal_handler;
sigaction(SIGRTMIN + 3, &action, &oldHandler );
// send signal to affected thread
pthread_kill( threadId, SIGRTMIN + 3 );
// restore original signal handler
sigaction( SIGRTMIN + 3, &oldHandler, NULL );
}
该线程确实收到SIG37,然后整个应用程序终止。信号处理程序完成后,程序/线程是否应该继续执行?
致谢
答案 0 :(得分:0)
主要问题是restore original signal handler
执行得太早了。
我编写了一个SystemTap脚本来跟踪do_sigaction
和do_signal
,如下所示:
probe begin {
printf("start.\n");
}
probe kernel.function("do_signal") {
if ("test_sigaction" == execname()) {
printf("do_signal pid=%d\n", pid());
}
}
probe kernel.function("handle_signal") {
if ("test_sigaction" == execname()) {
printf("handle_signal pid=%d\n", pid());
}
}
probe kernel.function("do_sigaction").return {
if ("test_sigaction" == execname()) {
printf("do_sigaction: ret=%d sig=%d act=%p oact=%p pid=%d\n",
$return, @entry($sig), @entry($act),
@entry($oact), pid());
}
}
结果是
do_sigaction: ret=0 sig=37 act=0xffffc90006ccbec8 oact=0xffffc90006ccbee8 pid=45920 //STEP1
do_sigaction: ret=0 sig=37 act=0xffffc90006ccbec8 oact=0x0 pid=45920 //STEP2
do_signal pid=45920 //STEP3
do_signal pid=45920
原因:
很显然这里存在并发问题。 在执行do_signal之前可以恢复信号处理程序。 在还原信号处理程序之前,或将还原处理程序移至my_signal_handler函数之前,需要并发控制,例如:
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
struct sigaction oldHandler;
void my_signal_handler(int signo, siginfo_t *info, void *extra)
{
printf("my signal handler\n" );
// restore original signal handler
sigaction( SIGRTMIN + 3, &oldHandler, NULL );
}
int threadsupervisor(pthread_t thread_id)
{
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = my_signal_handler;
sigaction(SIGRTMIN + 3, &action, &oldHandler );
// send signal to affected thread
pthread_kill(thread_id, SIGRTMIN + 3 );
return 0;
}
void *test_thread(void *args)
{
long loop = 0;
while(1) {
printf("sleep %ld\n", ++loop);
sleep(1);
}
return (void *)NULL;
}
int main()
{
pthread_t thread_id;
pthread_create(&thread_id, NULL, test_thread, NULL);
threadsupervisor(thread_id);
pthread_join(thread_id, NULL);
return 0;
}