Как отслеживать все процессы-потомки для очистки? - PullRequest
8 голосов
/ 04 августа 2011

У меня есть программа, которая может fork() и exec() несколько процессов в цепочке. Например: процесс A -> fork, exec B -> fork, exec C -> fork, exec D. Итак, A пра-пра-пра-прародитель C.

Теперь проблема в том, что я не имею никакого контроля над процессами B, C и D. Поэтому может произойти несколько вещей.

  1. Может так случиться, что процесс-потомок может setsid() изменить свою группу процессов и сеанс.
  2. Или один из потомков умирает (скажем, C), и, следовательно, его потомок (D) происходит от init.

Поэтому я не могу полагаться на идентификатор группы процессов или идентификатор родителя для отслеживания всех потомков A. Есть ли надежный способ отслеживания всех потомков? Точнее говоря, я хотел бы убить всех потомков (сирот и т. Д.).

Было бы также замечательно, если бы он соответствовал POSIX.

Ответы [ 2 ]

4 голосов
/ 04 августа 2011

POSIX способ сделать это просто использовать группы процессов. Потомки, которые явно изменяют свою группу процессов / сеанс, принимают преднамеренное решение , а не , чтобы их жизнь отслеживалась их исходным родителем - они специально освобождают себя от родительского контроля. Такие процессы не являются сиротами - они взрослые, которые «полетели из гнезда» и хотят контролировать свою жизнь.

2 голосов
/ 04 августа 2011

Я согласен с общим настроением caf : если процесс вызывает setsid, он говорит, что хочет жить самостоятельно, несмотря ни на что.Вы должны тщательно продумать, действительно ли вы хотите их убить.

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

Чистое решение - запускать процессы в своей виртуальной среде.,Это может быть jail в стиле FreeBSD, Linux cgroups или любой другой вид технологии виртуализации.Ограничения этого подхода заключаются в том, что технологии виртуализации зависят от ОС, и процессы будут работать в несколько ином контексте.

Если у вас есть только один экземпляр этих процессов в системе, и вы можете подключиться к корню, запустите процессы как выделенный пользователь.Супер-сеанс определяется как процессы, выполняемые как выделенный пользователь.Убейте потомков с помощью kill(-1, signum) (обратите внимание, что это убьет сам процесс-убийцу, если он не заблокирован или не обработал сигнал).

Вы можете сделать процесс открытым уникальным файлом, убедившись, что флаг FD_CLOEXECустанавливается в дескрипторе файла.Все дочерние процессы будут наследовать открытый файл, если они явно не уберут флаг FD_CLOEXEC перед вызовом execve или не закроют файл.Убить процессы с помощью fuser -k или получить список идентификаторов процессов с помощью fuser или lsof (fuser в POSIX, но не fuser -k.) Обратите внимание, что существует условие гонки: процесс может быть разветвлен междувремя, когда вы звоните fuser, и время, когда вы убиваете его;поэтому вам нужно вызывать fuser в цикле до тех пор, пока больше не появятся процессы (не повторяйте цикл, пока все процессы не будут остановлены, поскольку это может быть бесконечный цикл, если один из процессов блокирует ваш сигнал).

Вы можете сгенерировать уникальную случайную строку и определить переменную окружения с этим именем или с хорошо известным именем и этой уникальной строкой в ​​качестве значения.Он будет унаследован всеми процессами-потомками, если они не решат изменить свою среду.Не существует портативного способа поиска процессов на основе их среды или даже получения среды другого процесса.Во многих вариантах Unix вы можете получить информацию с опцией ps (например, ps -e на * BSD или ps e на Linux);Анализ информации может быть непростым, но наличие уникальной строки является достаточным показателем.Как и в случае с fuser выше, обратите внимание на необходимость цикла, чтобы избежать состояния гонки, если потомок вызывает fork слишком поздно, чтобы вы заметили его потомка, но прежде чем вы смогли убить родителя.

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

...