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

#linux #process

#linux #процесс

Вопрос:

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

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

Комментарии:

1. Лучший способ получить информацию — быть родительским процессом и wait для него. Таким образом, вы можете либо запросить родительский процесс (например, родитель может предоставить интерфейс или записать данные), либо вы можете стать родителем (через ptrace).

Ответ №1:

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

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

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

Ответ №2:

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

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

Кроме того, я не вижу, в чем разница между (b) и (c): в обоих случаях они получат сигнал, который они могут либо перехватить, заблокировать, либо проигнорировать ( SIGKILL за исключением — or 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 также имеет интерфейс netlink proc connector, который позволяет вам отслеживать процессы, не останавливая их и не влияя на них каким-либо образом. Однако он работает только как root. Пример программы, использующей интерфейс proc connector forkstat(1) :

 forkstat -e exit   # will show all exiting processes
stdbuf -oL forkstat -e exit | grep -m1 PID  # will only show when PID exits