Подтвердить что ты не робот

Longjmp из обработчика сигнала?

Из вопроса:

Хорошая практика программирования для использования setjmp и longjmp в C?

Два комментария остались:

"Вы не можете генерировать исключение в обработчике сигналов, но вы можете сделать longjmp безопасно - пока вы знаете, что делаете. - Дитрих Epp 31 августа в 19:57        @Dietrich: +1 к вашему комментарию. Это малоизвестный и полностью недооцененный факт. Существует ряд проблем, которые не могут быть решены (неприятные условия гонки) без использования longjmp из обработчики сигналов. Асинхронное прерывание блокировки системных вызовов - это классический пример".

У меня создалось впечатление, что обработчики сигналов вызывались ядром, когда он сталкивался с исключительным условием (например, делением на 0). Кроме того, они вызываются, только если вы их зарегистрируете.

Это, по-видимому, подразумевает (для меня), что они не вызываются через ваш обычный код.

Перейдя к этой мысли... setjmp и longjmp, как я их понимаю, предназначены для свертывания стека к предыдущей точке и состоянию. Я не понимаю, как вы можете свернуть стек, когда обработчик сигнала вызывается с момента его вызова из ядра как одноразовое обстоятельство, а не из вашего собственного кода. Какая следующая вещь в стеке от обработчика сигнала??

4b9b3361

Ответ 1

longjmp не выполняет нормальное стекирование. Вместо этого указатель стека просто восстанавливается из контекста, сохраненного setjmp.

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

Ответ 2

То, как ядро ​​ "вызывает" обработчик сигналов, прерывает поток, сохраняя маску сигнала и состояние процессора в структуре ucontext_t в стеке, находящемся за пределами (ниже, при реализации роста), прерванный стек кода указатель и перезапуск выполнения по адресу обработчика сигнала. Ядру не нужно отслеживать состояние "этот процесс в состоянии обработчика сигнала"; что полностью является следствием созданного нового кадра вызова.

Если прерванный поток находился посреди системного вызова, ядро ​​вернется из кода ядра и настроит адрес возврата для повторения системного вызова (если для сигнала установлен SA_RESTART, а системный вызов - перезапустимый) или поместите EINTR в код возврата (если он не перезапускается).

Следует отметить, что longjmp является асинхронным сигналом-небезопасным. Это означает, что он вызывает поведение undefined, если вы вызываете его из обработчика сигнала, если сигнал прервал другую несинхронизируемую функцию асинхронного сигнала. Но до тех пор, пока прерванный код не использует библиотечные функции или использует только библиотечные функции, помеченные как безопасные для асинхронного доступа, законно вызывать longjmp из обработчика сигналов.

Наконец, мой ответ основан на POSIX, так как вопрос помечен unix. Если бы вопрос касался только чистого C, я подозреваю, что ответ несколько иной, но сигналы бесполезны без POSIX в любом случае...

Ответ 3

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

Ответ 4

Вы не можете использовать longjmp, чтобы выйти из обработчика сигнала.

Причиной этого является то, что setjmp сохраняет только ресурсы (регистры процессов) и т.д., что соглашение о вызове указывает, что должно быть сохранено в результате простого вызова функции.

Когда происходит прерывание, прерываемая функция может иметь гораздо большее состояние, и она не будет восстановлена ​​правильно longjmp.