简体   繁体   English

信号处理程序终止程序

[英]Signal handler terminates program

I try to install a signalhandler using sigaction and then call it on a single thread like this: 我尝试使用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 );
}

The thread does receive a SIG37, then the whole application terminates. 该线程确实收到一个SIG37,然后整个应用程序终止。 Shouldn't the program/thread continue after the signal handler is done? 信号处理程序完成后,程序/线程是否应该继续执行?

Regards 问候

The main problem is that the restore original signal handler is executed too early. 主要问题是restore original signal handler执行得太早。

I wrote a SystemTap script to trace do_sigaction and do_signal , as follows: 我编写了一个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());
    }
}

The result is 结果是

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

The reason: 原因:

  • STEP1: set signal handler to my_signal_handler in main thread STEP1:在主线程中将信号处理程序设置为my_signal_handler
  • STEP2: restore original signal handler in main thread STEP2:在主线程中还原原始信号处理程序
  • STEP3: do_signal is executed when the child thread returns from kernel mode to user mode. STEP3:当子线程从内核模式返回到用户模式时,将执行do_signal。

Obviously there are concurrency issues here. 显然这里存在并发问题。 It is possible to restore the signal handler before executing do_signal. 在执行do_signal之前可以恢复信号处理程序。 Concurrent control is required before restore the signal handler, or move restore handler to my_signal_handler function, like as: 在还原信号处理程序之前,或将还原处理程序移至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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM