Точки отмены в обработчиках сигналов? - PullRequest
6 голосов
/ 21 ноября 2010

Что произойдет, если программа вызовет функцию, которая является точкой отмены из обработчика сигнала?Существует ряд функций, которые POSIX определяет как безопасные для асинхронного сигнала и точки отмены.Если обработчик сигнала вызывает такую ​​функцию и выполняется отмена, результат будет очень похож на то, что произошло бы, если бы поток включил асинхронное отмену - на самом деле намного хуже, потому что все обработчики очистки отмены, которые, вероятно, не являются асинхронными-сигнальнымиsafe, вызывается из контекста обработчика сигнала.

Что POSIX на самом деле указывает в этом случае и что на самом деле делают реализации?Я не могу найти ни одного языка в POSIX, который бы запретил действие точек отмены в обработчиках сигналов, ни такой защиты в источнике glibc / nptl.

1 Ответ

3 голосов
/ 24 ноября 2010

Я не знаю, что POSIX даже осмелился упомянуть эту тему, но я не провел исчерпывающий поиск.

Некоторое краткое экспериментирование с системой gcc / nptl показывает, что, как я и подозревал, и я думаю, вы это сделали, такой защиты нет в NPTL - обработчики отмены действительно вызываются из контекста обработчика сигнала.

Программа ниже (извиняюсь за хакерство и т. Д.) Отображает следующий вывод:

Signal handler called
Sent cancellation
Cleanup called
In sighandler

... указывает, что:

  • обработчик сигнала вызван
  • другой поток затем называется pthread_cancel()
  • Затем вызывается обработчик отмены без завершения обработчиком сигнала

Вот программа:

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

pthread_t mainthread;

int in_sighandler = 0;

void
cleanup (void *arg)
{
    write(1, "Cleanup called\n", strlen("Cleanup called\n"));
    if (in_sighandler) {
        write(1, "In sighandler\n", strlen("In sighandler\n"));
    } else {
        write(1, "Not in sighandler\n", strlen("In sighandler\n"));
    }
}


void
sighandler (int sig, siginfo_t *siginfo, void *arg)
{
    in_sighandler = 1;
    write(1,"Signal handler called\n", strlen("Signal handler called\n"));  // write() is a CP
    usleep(3000000); // usleep() is a CP; not strictly async-signal-safe but happens to be so in Linux
    write(1, "Signal handler exit\n", strlen("Signal handler exit\n"));
    in_sighandler = 0;
}

void *
thread (void *arg)
{
    sleep(1);
    pthread_kill(mainthread, SIGUSR1);
    usleep(500000);
    pthread_cancel(mainthread);
    printf("Sent cancellation\n");
    return (NULL);
}

int
main (int argc, char **argv)
{
    int rc;
    struct sigaction sa;
    pthread_t threadid;

    mainthread = pthread_self();

    // Set up a signal handler to test its cancellation properties
    sa.sa_sigaction = &sighandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    rc = sigaction(SIGUSR1, &sa, NULL);
    assert(rc == 0);

    // Set up a thread to send us signals and cancel us
    rc = pthread_create(&threadid, NULL, &thread, NULL);
    assert(rc == 0);

    // Set up cleanup handlers and loop forever
    pthread_cleanup_push(&cleanup, NULL);
    while (1) {
        sleep(60);
    }
    pthread_cleanup_pop(0);
    return (0);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...