longjmp () от обработчика сигналов

Выезд эта страница , которая имеет пример того, как сделать это.

5
задан sttwister 11 November 2009 в 14:39
поделиться

6 ответов

На странице руководства для longjmp:

POSIX не указывает, следует ли longjmp () восстановит сигнал контекст. Если вы хотите сэкономить и восстановите маски сигналов, используйте siglongjmp ()

Ваш второй вопрос: Да, функция вернет -2, потому что longjmp () заставит его перейти в setjmp (буфер) часть, но время должно быть очень точным.

7
ответ дан 13 December 2019 в 05:37
поделиться

Когда дело доходит до того, что может пойти не так, когда поведение не определено, единственный ответ, на который вы можете рассчитывать, - «все, в том числе ничего». Может быть, что-то пойдет не так, возможно, вы получите segfault, возможно, у вас будут носовые демоны.

Более конкретные ответы зависят от того, с какой системой и выпуском вы работаете. Например, в дистрибутивах Linux (по крайней мере, все с 2000 года) ядро ​​выполняет некоторые задачи после возврата обработчика сигналов. Если вы используете longjmp, вы, вероятно, оставите в стеке ядра мусор, который может вызвать проблемы в дальнейшем, например, ошибочный возврат к коду, который ваша программа выполняла, когда сигнал был пойман (вызов 'fgets' в примере). Или нет.

Вызов longjmp в обработчике сигнала также может (в общем,

2
ответ дан 13 December 2019 в 05:37
поделиться

Я не думаю, что вам нужно использовать setjmp / longjmp . fgets должен прерываться сигналами (для errno задано значение EINTR), хотя вам, вероятно, потребуется использовать sigaction (...) вместо signal (... ) , чтобы убедиться, что SA_RESTART очищен.

void timeout(int) {
   // doesn't actually need to do anything
}
int t_gets(char* s, int t)
{
    char* ret;
    struct sigaction action = {0};
    action.sa_handler = timeout;
    sigaction(SIGALRM, &action, NULL);
    alarm(t);
    // if fgets() does not return in t seconds, SIGALARM handler timeout()
    // will be called, interrupting fgets and causing t_gets() to return -2
    ret = fgets(s, 100, stdin);
    // even if the alarm is called after fgets returns, it won't erroneously cause
    // t_gets to return -2
    int err = errno;
    alarm(0);
    if (ret == NULL) { 
        switch (err) {
        case EINTR:
            return -2;
        // add other cases as warranted
        default:
            return -1;
        }
    }
    return strlen(s);
}
1
ответ дан 13 December 2019 в 05:37
поделиться

По поводу второго вопроса: вы можете добавить блокировку, которая блокирует возврат -2, когда основной поток прошел вызов fgets.

0
ответ дан 13 December 2019 в 05:37
поделиться

что делать, если тревога срабатывает сразу после fgets () возвращает, но до тревоги (0) вызывается?

Вы можете инициализировать ret (возможно, равным NULL) и проверить это в теле оператора if (setjmp ()) :

/* NOT TESTED */
int t_gets(char* s, int t)
{
    char* ret = NULL;
    signal(SIGALRM, timeout);
    if (setjmp(buffer) != 0) {
        // timeout() will jump here
        if (ret == NULL) {
            return -2;
        } else {
            goto end_of_function;
        }
    }
    alarm(t);
    // if fgets() does not return in t seconds, SIGALARM handler timeout()
    // will be called, causing t_gets() to return -2
    ret = fgets(s, 100, stdin);
end_of_function:
    alarm(0);
    if (ret == NULL ) return -1;
    return strlen(s);
}
0
ответ дан 13 December 2019 в 05:37
поделиться

Вы можете заменить longjmp / setjmp на siglongjmp / sigsetjump, и тогда не будет проблемы с неопределенным контекстом сигнала после jmp. Возможно, вам все равно, поскольку вы явно не меняете маску. Я забываю, изменяется ли маска самим сигнальным вызовом.

Возможно, более серьезной проблемой является обеспечение безопасности вашего кода для сигналов. Например, получает ли fgets () какой-либо мьютекс (возможно, неявно как часть вызова malloc)? Если это так, и ваш таймер отключится, пока этот мьютекс удерживается, ваша программа будет всплывать в следующий раз, когда вы попытаетесь выделить кучу.

0
ответ дан 13 December 2019 в 05:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: