Обработка сигналов в C с процессом и 2 потоками не работает - PullRequest
2 голосов
/ 10 сентября 2011

Я работаю со следующим примером (который основан на примере в man-странице для pthread_sigmask в linux):

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>

/* Simple error handling functions */

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void * silly_worker(void *arg)
{
  for(int index=0,max=5; index<max; ++index) {
    printf("waiting %d of %d\n",index,max);
    sleep(1);
  }
  puts("Finished waiting.  Here comes the SIGSEGV");
  strcpy(NULL,"this will crash");
}

static void *
sig_thread(void *arg)
{
    sigset_t *set = (sigset_t *) arg;
    int s, sig;

    for (;;) {
        s = sigwait(set, &sig);
        if (s != 0)
            handle_error_en(s, "sigwait");
        printf("Signal handling thread got signal %d\n", sig);
    }
}

int
main(int argc, char *argv[])
{
    pthread_t thread;
    pthread_t thread2;
    sigset_t set;
    int s;

    /* Block SIGINT; other threads created by main() will inherit
       a copy of the signal mask. */

    sigemptyset(&set);
    sigaddset(&set, SIGQUIT);
    sigaddset(&set, SIGUSR1);
    sigaddset(&set, SIGSEGV);
    s = pthread_sigmask(SIG_BLOCK, &set, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_sigmask");

    s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    /* Main thread carries on to create other threads and/or do
       other work */

    s = pthread_create(&thread2, NULL, &silly_worker, (void *) &set);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    pause();            /* Dummy pause so we can test program */
}

Согласно man-странице, это должно перехватить SIGSEGV, сгенерированный потоком silly_worker. Но это не так. На самом деле я не уверен, какое агентство получает сигнал вообще. Когда программа запускается, я получаю следующий вывод:

waiting 0 of 5
waiting 1 of 5
waiting 2 of 5
waiting 3 of 5
waiting 4 of 5
Finished waiting.  Here comes the SIGSEGV
Segmentation fault

Вы можете видеть, что обработчик сигнала не выводит строку "Ошибка сегментации", поэтому она должна исходить из обработчика по умолчанию. Если значение по умолчанию, то это как бы портит цель примера - установить обработчик сигнала, захватить сигналы и что-то с ними сделать.

Я могу найти множество примеров обработчиков, но ни один из них не подходит для этой ситуации: ни один из них не демонстрирует поток, который вызывает действительно очевидный SIGSEGV, и перехватывает и сообщает об ошибке в своем пользовательском обработчике.

Остается вопрос: как получить специальный обработчик сигнала для получения сигнала из этого потока SIGSEGV?

1 Ответ

1 голос
/ 10 сентября 2011

SIGSEGV из недопустимых обращений к памяти (в отличие от «поддельного», отправленного kill или sigqueue), отправляется потоку, который выполнил недопустимый доступ к памяти, а не всему процессу. Таким образом, у вас не может быть выделенного потока-обработчика сегфоутов. Если вы хотите обработать это, вы должны обработать это в потоке, где это произошло. (Причина, по которой вы видите оболочку print Segmentation fault, заключается в том, что, когда SIGSEGV блокируется в потоке и возникает ошибка, ядро ​​выполняет действие по умолчанию, убивающее процесс. На самом деле это UB для POSIX, но это как Linux обращается с UB.)

Обратите внимание, однако, что у вас может быть обработчик сигнала для SIGSEGV, инициирующий действие выделенным потоком. Уродливый способ сделать это - использовать другой сигнал, который вы можете отправить (вместе с аргументом) через sigqueue. Более чистый (на мой взгляд, по крайней мере) способ сделать это - использовать обработчик SIGSEGV, использующий sem_post, который безопасен для асинхронного сигнала и может использоваться для пробуждения другого потока, ожидающего семафор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...