Не получает SIGCHLD для процессов, выполняемых с помощью sudo - PullRequest
11 голосов
/ 22 ноября 2011

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

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

Когда я получаю команду, такую ​​как sudo ls, я выполняю программу sudo и затем предоставляю ls в качестве параметра. Я выполняю это выполнение с execvp.

Если я посмотрю на ps -aux после того, как моя оболочка выполнила sudo ls, я увижу следующее:

root      4795  0.0  0.0   4496  1160 pts/29   S+   16:51   0:00 sudo ls
root      4796  0.0  0.0      0     0 pts/29   Z+   16:51   0:00 [ls] <defunct>

Итак, sudo побежал и получил назначение pid = 4795, а ребенку (ls) - 4796. Ребенок выполнил свою задачу и теперь сидит в состоянии зомби. sudo не хочет пожинать зомби-процесс и просто сидит там.

Я хотел бы знать, что является причиной этого поведения - я пробовал различные методы для очистки этих процессов зомби, такие как запуск моей оболочки под sudo и ожидание непосредственно на sudo и PID, который sudo выполняется (4796 в приведенном выше примере). Ни один из этих методов не сработал.

Как всегда, любые советы приветствуются.

1 Ответ

4 голосов
/ 25 ноября 2011

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

Прежде всего, я не знаю, используете ли вы устаревшие функции signal () или новые процедуры POSIX sigaction ()ловить сигналы.sigset () полезен между GNU.

Legacy Signals - signal ()
Почти невозможно, если вообще невозможно, гарантировать герметичностьпроцессор сигналов, использующий оригинальный процессор сигналов во всех средах.

  • В некоторых системах UNIX входящий обработчик сигнала может сбросить обработчик до состояния по умолчанию.Последующие сигналы гарантированно будут потеряны, если только обработчик явно не сбросит сигнал.
  • обработчики signal () не должны предполагать, что их вызывают один раз для каждого сигнала.
    • Обработчики должны выполнять цикл while( ( pid = waitpid( -1, &signal, WNOHANG ) ) > 0 ), пока не будет найдено больше сигналов, поскольку устаревшие сигналы не устанавливаютсостояние bool, указывающее хотя бы один сигнал, является выдающимся.Фактический счет неизвестен.
    • Обработчики должны допускать отсутствие сигналов, если предыдущий цикл while () обработал сигнал.
  • Разрешить сигналы от неизвестных процессов ... если программа, которую вы запускаете, также запускает процесс внука, вы можете унаследовать этот процесс, если ваш ребенок быстро завершит работу.

Советуйте, держите нос и бегите от устаревших сигналов.

Отсутствие цикла while () в унаследованном обработчике и нескольких SIGCHILD, одного из вашего sudo и одного или нескольких из неожиданных уволенных внуковот судо.Если при поступлении сигнала внука обрабатывается только один SIGCHILD, ожидаемый сигнал программы не будет перехвачен.

POSIX Signals - sigaction ()
POSIX сигналыможет убрать все сбои устаревших сигналов.

  • Установить обработчик без восстановления (восстановление НЕ является частью сигналов POSIX и часто, по моему мнению, является злом, когда вы можете получитьболее одного сигнала для обработки таким же образом).
  • sigaction () сигналы липкие ... они живут до тех пор, пока явно не изменятся (замечательно!).Ни одно из этих трудоемких требований повторной установки обработчика сигнала в обработчике.
  • Установить маску для маскировки текущего сигнала при обработке сигнала.Параноики также будут маскировать любой другой сигнал, передаваемый тому же обработчику.

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

GNU - sigset()
GNU предоставляет полезный промежуточный элемент, который имеет те же сигнатуры вызова, что и signal (), но устраняет большинство проблем.Некоторые дополнительные функции управления также доступны.Использование sigset () легко решает многие проблемы с сигналом.

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

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

...