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

Как выполняются асинхронные обработчики сигналов в Linux?

Я хотел бы точно знать, как работает обработка асинхронных обработчиков сигналов в Linux. Во-первых, я не понимаю, какой поток выполняет обработчик сигнала. Во-вторых, я хотел бы знать шаги, которые выполняются, чтобы поток выполнял обработчик сигнала.

По первому вопросу я прочитал два разных, казалось бы, противоречивых объяснения:

  • Ядро Linux, by Andries Brouwer, §5.2 состояния "Принимающие сигналы" :

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

  • Вопрос StackOverflow "Работа с асинхронными сигналами в многопоточной программе" приводит меня к мысли, что поведение Linux как SCO Unix:

    Когда сигнал доставляется процессу, если он пойман, он будет обрабатываться одним и только одним из потоков, удовлетворяющих одному из следующих условий:

    • Поток заблокирован в sigwait (2) системный вызов, аргумент которого включает тип сигнала пойманного.

    • Поток, сигнальная маска которого не включает тип пойманного сигнала.

    Дополнительные соображения:

    • В потоке, заблокированном в sigwait (2), предпочтение отдается потоку, не блокирующему тип сигнала.
    • Если более чем один поток отвечает этим требованиям (возможно, два потока вызывают sigwait (2)), то один из них будет выбран. Этот выбор не предсказуем прикладными программами.
    • Если нить не подходит, сигнал будет оставаться "ожидающим" на уровне процесса, пока не будет принят какой-либо поток.

    Кроме того, "Модель обработки сигналов Linux" по состояниям Moshe Bar "Асинхронные сигналы доставляются в первый поток, который не блокирует сигнал.", который я интерпретирую как означающий, что сигнал доставляется в какой-либо поток, имеющий свою сигмаску, не включающую сигнал.

Какой из них правильный?

Во втором случае, что происходит со стеком и регистрирует содержимое для выбранного потока? Предположим, что обработчик потока для запуска-сигнала находится в середине выполнения функции do_stuff(). Используется ли поток T-стека непосредственно для выполнения обработчика сигнала (т.е. Адрес батута сигнала помещается в стек T, а поток управления переходит к обработчику сигнала)? Альтернативно, используется отдельный стек? Как это работает?

4b9b3361

Ответ 1

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

С учетом сказанного, объяснение №2 гораздо более подробное, полное и правильное.

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