Что происходит, если обработчик сигнала вызывается в точке отмены? - PullRequest
10 голосов
/ 23 марта 2011

Предположим, что приложение заблокировано в точке отмены, например, read, и сигнал получен и вызван обработчик сигнала.Glibc / NPTL реализует точки отмены, позволяя асинхронную отмену на время системного вызова, поэтому, насколько я могу судить, асинхронная отмена будет действовать в течение всей продолжительности обработчика сигнала.Это, конечно, было бы ужасно неправильно, так как есть множество функций, которые не безопасны при асинхронной отмене, но которые необходимы для безопасного вызова из обработчиков сигналов.

Это оставляет меня с двумя вопросами:

  • Я ошибаюсь или поведение glibc / NPTL действительно так опасно нарушено?Если да, то соответствует ли такое опасное поведение?
  • Что, согласно POSIX, должно происходить, если обработчик сигнала вызывается во время выполнения процессом функции, являющейся точкой отмены?

Редактировать: Я почти убедил себя, что любой поток, который является потенциальной целью pthread_cancel, должен гарантировать, что функции, которые являются точками отмены, никогда не могут быть вызваны из обработчика сигнала в контексте этого потока:

С одной стороны, любой обработчик сигнала, который может быть вызван в потоке, который может быть отменен и который использует любые функции async-cancel-unsafe должен отключить отмену перед вызовом любой функции, котораяточка отмены.Это связано с тем, что с точки зрения кода, прерванного сигналом, любое такое аннулирование будет эквивалентно асинхронному аннулированию.С другой стороны, обработчик сигнала не может отключить отмену, если только код, который будет работать при вызове обработчика сигнала, использует только функции, безопасные для асинхронного сигнала, поскольку pthread_setcancelstate не является асинхронным сигналомсейф.

Ответы [ 3 ]

4 голосов
/ 20 апреля 2011

Чтобы ответить на первую половину моего собственного вопроса: glibc демонстрирует поведение, которое я предсказал.Обработчики сигналов, которые работают в режиме блокировки в точке отмены, работают в режиме асинхронного отмены.Чтобы увидеть этот эффект, просто создайте поток, который вызывает точку отмены, которая будет блокировать навсегда (или на долгое время), подождет минуту, отправит ей сигнал, снова подождите секунду, отменит и присоединится к ней.Обработчик сигнала должен возиться с некоторыми изменчивыми переменными таким образом, чтобы было ясно, что он работал в течение непредсказуемого периода времени, прежде чем завершится асинхронно.

Что касается того, позволяет ли POSIX такое поведение, я все еще не% определенный.POSIX сообщает:

Всякий раз, когда для потока включена возможность отмены, и был сделан запрос на отмену с этим потоком в качестве цели, и поток затем вызывает любую функцию, которая является точкой отмены (например, pthread_testcancel ()или read ()), запрос отмены должен быть обработан до возврата функции.Если для потока включена возможность отмены и запрос отмены сделан с потоком в качестве цели, в то время как поток приостановлен в точке отмены, поток должен быть разбужен, и запрос отмены должен быть обработан.Не определено, выполняется ли запрос отмены или запрос отмены остается ожидающим, и поток возобновляет нормальное выполнение, если:

  • Поток приостанавливается в точке отмены, и событие, для которогоожидание происходит

  • Заданный тайм-аут истек

до того, как запрос отмены будет обработан.

Предположительновыполнение обработчика сигнала не означает «приостановку», поэтому я склоняюсь к интерпретации поведения glibc здесь как неконформного.

1 голос
/ 10 января 2014

Rich,

Я сталкивался с этим вопросом, когда делал обзор документации по безопасности для AC, над которой Алекс Олива работал над glibc.

По моему мнению, реализация библиотеки GNU C Library (на основе nptl) не сломан.Хотя верно то, что асинхронное аннулирование включено для блокировки системных вызовов (которые должны быть точками аннулирования), такое поведение все равно должно быть согласованным.

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

Также верно, что если другой поток вызывает pthread_cancel с целевым потоком сигнала, то такая отмена будетдействовал немедленно.Это по-прежнему соответствует формулировке POSIX «до того, как функция вернется» (в этом случае чтение не вернулось, а целевой поток находится в обработчике сигнала).

Проблема с сигналом заключается в том, что он вызываетпоток должен находиться в двух одновременных состояниях, как постоянно в точке отмены, так и выполнять инструкции.Если поступает запрос на отмену, то, по моему мнению, он соответствует немедленно.Хотя группа Austin могла бы уточнить.

Проблема с реализацией glibc заключается в том, что для нее требуются все обработчики сигналов, выполняемые потоком, подлежащим отмене.вызывать только асинхронно-безопасные функции отмены.Это неочевидное требование, которое не вытекает из стандарта, но не делает его несовместимым.

Возможное решение для устранения хрупкости обработчиков сигналов:

  • Не включайте асинхронное аннулирование для блокировки системных вызовов, вместо этого включите новый бит IN_SYSCALL в реализации отмены.

  • Когда вызывается pthread_cancel и для целевого потока установлено IN_SYSCALL, тогдаотправьте SIGCANCEL в поток, как обычно, для async-cancel, но обработчик SIGCANCEL ничего не делает (кроме побочного эффекта прерывания системного вызова).

  • Обертка вокруг системных вызововбудет искать отмену, которая была отправлена, и отменяет поток, прежде чем вернется оболочка.

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

Я думаю, что дальнейшее обсуждение должно произойти на Остин Гроуp Список рассылки как часть обсуждения стандартов POSIX или должен происходить на libc-alpha как phart обсуждения реализации glibc.

0 голосов
/ 23 марта 2011

Я думаю, что вы ищете, это сочетание двух вещей:

Некоторые системные вызовы могут прерываться сигналами, что приводит к возвращению ошибки EINTR. Это нормальное поведение, но мне никогда не было ясно, что происходит, если, например, вы находитесь в середине read - из потока ничего не читается? Возможно, кто-то может прокомментировать это, чтобы помочь уточнить.

Системные вызовы, которые не должны прерываться, например, те, о которых вы беспокоитесь, должны быть включены в вызовы sigprocmask (или pthread_sigmask в потоке) их от прерывания. После повторного включения сигналов все сигналы, полученные в заблокированном виде, будут доставлены. Как и в случае прерываний, однако, если вы блокируете слишком долго, вы можете пропустить некоторые из-за перезаписи (получение одного и того же сигнала несколько раз, считая один ожидающий сигнал).

...