通过PID获取进程的返回值

通过PID获取进程的返回值

如果我有一个被杀死的进程的 PID,我如何获得该进程的返回状态?

我特别想知道返回状态是 143 ( kill) 还是 137 ( kill -9),因为我不知道是什么终止了该进程。它是一个 Python 脚本,从我没有 root 访问权限的服务器上的 PHP 脚本运行。 Python 脚本运行几分钟,但 PHP 仅限运行 30 秒。 PHP 具有获取返回状态的功能,exec()但是如果 PHP 脚本超时,则该功能将不起作用!

答案1

这几乎肯定是由(默认)php.ini或等效设置决定的:

max_execution_time = 30

TLDR:如果您确定 PHP 确实首先退出,并且某些东西正在杀死您的脚本,那么您可以使用守护进程包装并监视Python进程(在非重新启动模式下,即没有--respawn),或添加信号处理机到 Python 脚本。

一般来说,如果您能够作为脚本的用户 ID 运行 shell,那么您应该能够stracetruss进程,例如在 Linux 上您可以相当有效地执行此操作:

 $ sleep 60 &
 [1] 10873
 $ strace -e trace=signal,process  -p $!
 Process 10873 attached - interrupt to quit
 +++ killed by SIGKILL +++
 Process 10873 detached

sleep进程由另一个终端的 终止kill -9kill -9但这并不常见,因为进程无法捕获它并干净地退出。

daemon使用以下变体进行监控:

daemon -i --errlog=/tmp/mypy.log -- /usr/bin/python [...]

这将记录任何与终止相关的信号。如果您想无论如何都记录每个退出,请添加--dbglog和。--debug=2

正如其他地方所指出的,如果该过程已经终止,那么它就消失了。只有父级(或 init)才能获取其退出代码,除非将其记录(可能使用进程记帐或审计),否则退出代码将丢失。

为了在 *nix 平台上进行内部超时处理,PHP 设置了一个SIGALARMSIGPROF 一个指定的超时。该信号处理程序只是调用内部zend_error()函数。然而,它也调用任何注册回调错误处理程序,这可能对您有用。

如果默认的错误处理程序启动,我相信 PHP 退出代码将是 255,因为超时是一个E_ERROR.

另请注意,退出代码约定为 128+N(其中 N 是信号编号)是由于某些 shell(包括bash)和许多 API 的行为造成的。信号后的实际进程退出代码取决于系统。这是大概只是信号编号,Linux 上通常是这种情况。这wait()组系统调用提供了进程退出的更好详细信息。 PHP 遵循 shell 约定,例如,如果您正在使用popen()pclose()当信号终止进程时,您将看到 128+N 作为退出代码。

这里的另一个考虑因素是 PHP 时间限制的行为,如果您检查set_time_limit()您将看到的文档

set_time_limit() 函数和配置指令max_execution_time仅影响脚本本身的执行时间。system()在确定脚本运行的最长时间时,不包括在脚本执行之外发生的任何活动所花费的时间,例如使用 的系统调用、流操作、数据库查询等。在 Windows 上情况并非如此,因为测量的时间是真实的。

您可以用一个简短的脚本来证明这一点:

<?php
# for (;;);
$exe="sleep 20";
print "exit code: " . pclose(popen($exe, 'r'));
?>

调用与time php -d max_execution_time=5 -f sleep3.php.该脚本将运行20秒,不会出现错误。如果您终止睡眠进程,例如kill -USR1 $(pgrep sleep)在另一个终端中,您将看到退出代码 138 (128+SIGUSR1)。

如果取消无限循环的注释for(;;),脚本将在 5 秒后终止。

答案2

已被终止的进程不再存在于系统中。事实上,在繁忙的主机上,一个长时间运行且被杀死的进程很有可能其 PID 已被其他进程重用,因此您最终会看到一些完全不相关的东西!

当一个进程被杀死时,不返回任何内容。它根本不复存在。这与可捕获信号(例如 HUP 或 USR1)形成鲜明对比,该信号处理(但不一定)以任何它认为合适的方式捕获和处理(包括使用定义的退出代码退出)。

如果您有足够的访问权限,您也许可以安装某种库或内核模块来拦截并记录系统调用,最终导致相关进程接收信号,但似乎更容易正如 pjc50 建议的那样只是添加包装脚本并在某处记录退出状态。

另一种选择是不让用户等待,而是让用户等待转向异步架构无论你正在做什么,都需要很长时间才能完成。

答案3

你要等待进程(),但我不知道 PHP 中是否可用。如果您不希望它被阻止,请不要忘记添加 WNOHANG。然而,只有当 PID 是调用进程的子进程时,这才有效。

最简单的方法可能是在 python 脚本周围放置一个包装脚本,将其终止状态记录在日志文件中的某个位置。

答案4

另一种选择:

来自 PHP:

exec("./wrapper.sh");

wrapper.sh

#!/bin/bash
./wrapperlogger.sh >/dev/null 2>&1 &

wrapperlogger.sh

./yourPythonScript
echo $? > exit_status.log

第一个包装器是该过程的后台。第二个包装器监视退出代码并将其记录到文件中。请注意,该脚本每次执行时都会覆盖相同的日志文件。

相关内容