信号处理程序终止程序

时间:2019-03-06 16:35:31

标签: c linux

我尝试使用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,然后整个应用程序终止。信号处理程序完成后,程序/线程是否应该继续执行?

致谢

1 个答案:

答案 0 :(得分:0)

主要问题是restore original signal handler执行得太早了。

我编写了一个SystemTap脚本来跟踪do_sigactiondo_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

原因:

  • STEP1:将信号处理程序设置为主线程中的my_signal_handler
  • STEP2:在主线程中还原原始信号处理程序
  • STEP3:子线程从以下位置返回时执行do_signal 内核模式到用户模式。

很显然这里存在并发问题。 在执行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;
}