Это происходит в StackOverflow, а не в SuperUser/ServerFault, поскольку это связано с системными вызовами и взаимодействием с ОС, выполняемыми sshd, а не с проблемой, с которой я использую SSH (хотя помощь в этом приветствуется, тоже :р).
Контекст:
Я запускаю сложную серию сценариев через SSH, например. ssh user@host -- /my/command
. Удаленная команда выполняет много сложных разветвлений и выполнения и в конечном итоге приводит к запуску фонового процесса демона на удаленном хосте. Иногда (я медленно схожу с ума, пытаясь выяснить надежные условия воспроизведения), команда ssh
никогда не возвращает управление клиентской оболочке. В таких ситуациях я могу зайти на целевой хост и увидеть процесс sshd: user@notty
без дочерних процессов, висящих на неопределенный срок.
Устранение этой проблемы не является тем, о чем этот вопрос. Этот вопрос касается того, что этот sshd
процесс делает.
Реализация SSH — OpenSSH, а версия — 5.3p1-112.el6_7.
Проблема:
Если я найду один из этих застрявших sshd
и strace
, я увижу, что он делает выбор на двух дескрипторах, например. select(12, [3 6], [], NULL, NULL
или аналогичный. lsof
сообщает мне, что один из этих дескрипторов — это TCP-сокет, соединяющийся с клиентом SSH. Другой — канал, другой конец которого открыт только в том же sshd
процессе. Если я ищу этот канал по идентификатору, используя ответ на этот вопрос суперпользователя, единственный процесс, который содержит ссылки на этот канал, — это тот же процесс. lsof
подтверждает это: оба конца канала для чтения и записи открыты в одном и том же процессе, например. (для трубы 788422703 и sshd
PID 22744):
sshd 22744 user 6r FIFO 0,8 0t0 788422703 pipe
sshd 22744 user 7w FIFO 0,8 0t0 788422703 pipe
Вопросы:
Чего ждет SSH? Если труба ни к чему не подключена и нет дочерних процессов, я не могу представить, какое событие она может ожидать.
Что это за «петлевая» труба / что она представляет? Моя единственная теория заключается в том, что, возможно, если STDIN не предоставляется клиенту SSH, целевой хост sshd
открывает фиктивный канал STDIN, чтобы часть его внутреннего кода управления дочерними элементами могла быть более единообразной? Но это кажется довольно шатким.
Как SSH попадает в эту ситуацию?
Что я пробовал/дополнительная информация:
- Первоначально я думал, что это утечка дескриптора к демону. Можно создать ожидающий процесс
sshd
без дочерних элементов, выполнив команду, которая работает в фоновом режиме, например.ssh user@host -- 'sleep 60 &'
;sshd
будет ждать закрытия потоков для демонизированного процесса; не только выход его непосредственного потомка. Поскольку рассматриваемые сценарии в конечном итоге приводят (вниз по дереву процессов) к запуску демона, изначально казалось возможным, что демон держится за дескриптор. Однако, похоже, это не так — используя командуsleep 60 &
в качестве примера,sshd
процессы, взаимодействующие с демонами, удерживают и выбирают четыре открытых канала, а не только два, а по крайней мере два из каналы подключены отsshd
к процессу демона, а не зациклены. Если не существует метода отслеживания/указания на канал, о котором я не знаю (а он, вероятно, есть — например, я понятия не имею, какdup
ed файловые дескрипторы играют вclose()
семафорное ожидание или конвейер), я не думаю, что канал Ситуация с самим собой представляет случай ожидания на демоне. sshd
периодически получает связь через TCP-сокет/ssh-соединение, что пробуждает его изselect
s на короткий период связи (во время которогоstrace
показывает, что он блокирует SIGCHLD), а затем возвращается к ожиданию на тех же FD.- Возможно, на меня влияет это состояние гонки (SIGCHLD доставляется до того, как ядро сделает данные доступными в конвейере). Однако это кажется маловероятным, учитывая скорость, с которой проявляется это состояние, и тот факт, что процессы, выполняемые на целевом хосте, являются сценариями Perl, а Среда выполнения Perl закрывается и сбрасывает дескрипторы открытых файлов при завершении работы.