Обработчик сигнала завершает программу - PullRequest
0 голосов
/ 06 марта 2019

Я пытаюсь установить обработчик сигналов, используя 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 голосов
/ 07 марта 2019

Основная проблема заключается в том, что 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

Причина:

  • 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...