Как отследить все процессы-потомки в Linux - PullRequest
0 голосов
/ 08 мая 2019

Я делаю библиотеку, которая должна порождать несколько процессов.

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

Поскольку для некоторых из них требуются демоны порождения(форк, форк, затем пусть родитель умирает), мы не можем найти все процессы путем итерации по дереву процессов.

В настоящее время мой подход таков:

  1. Регистрация обработчика с использованием os.register_at_fork
  2. На ветвь, в дочерний файл, скопируйте файл и добавьте (pid, process start time) в другой файл
  3. Затем, при необходимости, мы можем получить набор дочерних процессов, перебираязаписей в файле и сохраняющих те, где (pid, время начала процесса) соответствуют существующему процессу

Недостатки этого подхода:

  1. Работает только с multiprocessing или os.fork - не работает при порождении нового процесса Python с использованием subprocess или не-Python процесса.
  2. Блокировка вокруг вилки может сделать вещи более детерминированными во времятесты, чем они будут в действительности, скрывая условия гонки.

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

Альтернативы, которые я рассмотрел:

  1. Использование bcc для регистрации зондов форка / клона - проблема в том, что для этого требуется root, что, я думаю, было бы немного раздражающе для запуска тестов с точки участникаиз вида.Есть ли что-то подобное, что может быть сделано как непривилегированный пользователь только для текущего процесса и потомков?
  2. Использование strace (или ptrace), аналогичного описанному выше, - проблема в этом - влияние на производительность.Некоторые из тестов специально ориентированы на время запуска, а ptrace имеет относительно большие накладные расходы.Возможно, было бы меньше, если бы только отслеживание форка и клона, но это все еще конфликтует с желанием получить стеки на время ожидания теста.

Может кто-нибудь предложить подход к этой проблеме, который избегает ловушек инедостатки из вышеупомянутых?Меня сейчас интересует только Linux, и в идеале для него не нужно ядро ​​позже 4.15.

Ответы [ 2 ]

0 голосов
/ 24 мая 2019

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

  1. putenv("PID_DIR", <some tempdir>)
  2. Для текущего процесса переопределите fork и clone с версиямикоторый будет отслеживать время запуска процесса до $PID_DIR/<pid>.Переопределение выполняется с помощью plthook и применяется ко всем загруженным общим объектам.dlopen также следует переопределить для переопределения функций любых других динамически загружаемых библиотек.
  3. Установить библиотеку с реализациями __libc_start_main, fork и clone как LD_PRELOAD.

Начальная реализация доступна здесь используется как:

import process_tracker; process_tracker.install()

import os

pid1 = os.fork()
pid2 = os.fork()
pid3 = os.fork()

if pid1 and pid2 and pid3:
    print(process_tracker.children())
0 голосов
/ 08 мая 2019

Для subprocess.Popen, есть аргумент preexec_fn для вызываемого - вы можете взломать его.

В качестве альтернативы, посмотрите на cgroups (контрольные группы) -- Я считаю, что они могут справиться с такими сложными ситуациями, как создание демона и т. Д.

...