Как определить, почему процесс завершился программно в Linux - PullRequest
1 голос
/ 17 апреля 2019

Процессы прекращаются по одной из трех причин: они достигли конца выполнения (номинальный регистр), содержат необработанное исключение (синхронный сбой) или получили некоторый сигнал о том, что они не обрабатываются (асинхронный сбой),В рамках разработки программы мы можем найти способы, по крайней мере, для обнаружения каждого из них (например, операторов catch, обработчиков сигналов и т. Д.).

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

Ответы [ 2 ]

1 голос
/ 17 апреля 2019

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

В зависимости от ваших ограничений, существует несколько вариантов:

  1. wait - допускает быстрое уведомление (блокировка вызова или сигнала), но работает только для непосредственных детей.

  2. ptrace, напрямую (довольно сложно) или с помощью команды strace; у него есть ограничения, например один процесс может отслеживаться только одним процессом за раз, но он позволяет указать список системных вызовов для мониторинга, поэтому он не должен быть таким медленным, как вызов по умолчанию для strace.

  3. Учет процессов BSD. Обычно для доступа требуются права суперпользователя, и, безусловно, требуется, чтобы они включили его (это глобально). После запуска вы можете эффективно просматривать файл, который увеличивает запись для каждого завершающего процесса, включая код завершения / сигнал, либо программно (поле ac_exitcode в структуре acct), либо с помощью команды lastcomm (cf http://man7.org/linux/man-pages/man1/lastcomm.1.html).

0 голосов
/ 18 апреля 2019

Процессы прекращаются по одной из трех причин: (a) они достигли конца выполнения (номинальный случай), (b) они содержат необработанное исключение (синхронный сбой) ) или (c) они получили какой-то сигнал, что они не обрабатывают (асинхронный сбой).

Я не уверен, что должно означать (a) - даже если программа возвращается из своей функции main(), она по-прежнему завершается явным вызовом _exit(2) (или exit_group(2)) системный вызов (из кода времени выполнения C, который сначала вызывал main()). Если он не вызовет _exit(), он вылетит .

Кроме того, я не вижу разницы между (b) и (c) : они получат сигнал в обоих случаях - который они могут либо поймать, блокировать или игнорировать (кроме SIGKILL - или SIGSTOP, но последний не завершит процесс).

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

Затем вы должны имитировать то, что делают strace(1) или gdb(1): используйте ptrace(PTRACE_ATTACH) и т. Д. Например, это будет контролировать только выход процесса, а не все его системные вызовы:

strace -e trace=none -p PID   
strace -e trace=exit,exit_group -p PID

Интересна опция PTRACE_O_TRACEEXIT ptrace(2):

The tracee is stopped early during process exit, when registers are still available, allowing the tracer to see where the exit occurred, whereas the normal exit notification is done after the process is finished exiting.

В Linux также имеется интерфейс разъема proc, который позволяет отслеживать процессы, не останавливая и не затрагивая их каким-либо образом. Хотя это работает только как root. Пример программы с использованием интерфейса соединителя proc: forkstat(1):

forkstat -e exit   # will show all exiting processes
stdbuf -oL forkstat -e exit | grep -m1 PID  # will only show when PID exits
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...