如何获取可能意外终止的扭曲生成进程的退出代码?

How can I get exit code of a twisted spawn process which may be terminated unexpected?

我正在使用 twisted 生成本地进程,该进程可能会在某些情况下终止。

我有一个自定义的反应堆 twisted.internet.protocol.ProcessProtocol class。如果本地进程突然终止,我无法在 processEnded 中获取 return 值。 exitCode 设置为 None

一个mcv例子是这样的:

from twisted.internet import error,protocol,reactor

class MyPP(protocol.ProcessProtocol):
    def processEnded(self, reason):
        if reason.check(error.ProcessTerminated):
            err_info = "wrong termination: %s; exitCode: %s; signal: %s" % \
                        (reason, reason.value.exitCode, reason.value.signal)
            print(err_info)
        else:
            print("processEnded, status %d" % (reason.value.exitCode,))
            print("quitting")
        reactor.stop()

pp = MyPP()
reactor.spawnProcess(pp, "throw_exception", ["throw_exception"], {})
reactor.run()

并且 throw_exception 可执行文件可以编译自:

#include <iostream>
int main() {
    throw std::runtime_error("some exception");
    return 0;
}

执行 python 示例将打印

wrong termination: [Failure instance: Traceback (failure with no frames): : A process has ended with a probable error condition: process ended by signal 6. ]; exitCode: None; signal: 6

如果 shell 中的 运行,则 C++ 示例的 return 值为 134,这意味着 SIGABRT(6) 已发送。 (我还测试了发送 SIGINT 以终止但仍然没有退出代码。)

如何在ProcessProtocal实例中获取它?还是不可能?

在您的示例中,134 是 "wait status"(或者,在手册页中,是 "wstatus")。它编码了一些关于运行-状态转换的信息,该过程正在wait()进行。

可能的转换是:

  • 退出代码(即调用 exit(2)
  • 被信号杀死
  • 是否生成核心转储
  • 已停止(例如被 SIGSTOP
  • 未停止(例如 SIGCONT

POSIX提供了从等待状态中提取细节的宏:WIFEXITEDWIFSIGNALEDWTERMSIGWEXITSTATUS

Python 通过 os 模块公开这些:os.WIFEXITED,等等

os.WIFEXITED(134) 的计算结果为 Falseos.WIFSIGNALED(134) 的计算结果为真,os.WTERMSIG(134) 的计算结果为 6

ProcessDoneProcessTerminated 使用这些宏来提取信息并以稍微更有用的形式呈现它 - exitCodesignal 属性。

但是,

POSIX 没有提供一种方法来实现 other 方式。没有标准的 API 来构造一个 "wait status" 代表,比方说,"the process was killed by signal 6".

幸运的是,部分是因为没有办法倒退,Twisted 将异常的原始等待状态保留为 status 属性。如果您检查传递给 ProcessProtocolFailure 中包含的异常的属性,您应该找到您正在寻找的等待状态。