RFC-0074:公开进程开始时间 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 使进程开始时间可从用户空间查询。 |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2021-02-19 |
审核日期(年-月-日) | 2021-03-11 |
摘要
我们重构了 ZX_INFO_PROCESS
,以公开进程的开始时间,并清理描述其运行时的标志。我们说,当存在 ZX_INFO_PROCESS_FLAG_STARTED
标志时,进程具有有效的开始时间,并将其定义为调用 zx_process_start()
时的单调时间(如果有效)。
设计初衷
Chromium 先后依次提交至 crbug.com/726484 和 https://fxbug.dev/42105649,请求提供该功能,以便为跟踪事件提供基准时间,从而扩展支持 Linux、macOS 和 Windows 且不依赖于平台的接口。此外,提交 https://fxbug.dev/42119376 以利用这一功能,以便将正常运行时间纳入崩溃报告。
设计
在 ProcessDispatcher
的一个小型简单扩展中,我们会在 ProcessDispatcher::AddInitializedThread()
中记录初始线程的时间,然后在 ProcessDispatcher::GetInfo()
中传递它;前一种方法是 zx_process_start()
的主“启动”例程,而后一种方法是 zx_get_object_info()
的 zx_get_object_info()
方法,对应于具有 ZX_INFO_PROCESS
的进程句柄。
对于由 zx_object_get_info()
填充的结构体,目前我们有:
typedef struct zx_info_process {
// The process's return code; only valid if |exited| is true.
// If the process was killed, it will be one of the ZX_TASK_RETCODE values.
int64_t return_code;
// True if the process has ever left the initial creation state,
// even if it has exited as well.
bool started;
// If true, the process has exited and |return_code| is valid.
bool exited;
// True if a debugger is attached to the process.
bool debugger_attached;
uint8_t padding1[5];
} zx_info_process_t;
我们将其发展成以下形式:
typedef struct zx_info_process {
// The process's return code; only valid if the
// |ZX_PROCESS_INFO_FLAG_EXITED| flag is set. If the process was killed, it
// will be one of the |ZX_TASK_RETCODE| values.
int64_t return_code;
// The monotonic time at which zx_process_start() was called, only valid
// if the |ZX_INFO_PROCESS_FLAG_STARTED| flag is set.
zx_time_t start_time;
// Bitwise OR of ZX_INFO_PROCESS_FLAG_* values.
uint32_t flags;
uint8_t padding1[4];
} zx_info_process_t;
将为其引入以下标志值:
// Whether the process has started. zx_process_info_t::start_time is only
// valid if this flag is set.
#define ZX_INFO_PROCESS_FLAG_STARTED (1u << 0)
// Whether the process has exited.
#define ZX_INFO_PROCESS_FLAG_EXITED (1u << 1)
// Whether a debugger is attached to the process.
#define ZX_INFO_PROCESS_FLAG_DEBUGGER_ATTACHED (1u << 2)
“布尔值到标志”重构不是绝对必要的,但它会使 zx_info_process_t
与当前的系统调用结构体政策保持一致,在填充上节省一个字节,并且不会增加实施此方案所需的工作量(同时还能为下一个工程师省却大量麻烦)。
实现
将旧结构体重命名为
zx_info_process_v1_t
,并创建一个别名,以通过旧名称 (zx_info_process_t
->zx_info_process_v1_t
) 引用该结构。将主题ZX_INFO_PROCESS
重命名为ZX_INFO_PROCESS_V1
,并为旧名称创建别名 (ZX_INFO_PROCESS
->ZX_INFO_PROCESS_V1
)。添加新的结构体 (
zx_info_process_v2_t
) 和主题 (ZX_INFO_PROCESS_V2
)。更改内核以跟踪进程开始时间并识别新的主题和结构体。更新所有代码(树内和树外代码)以使用
ZX_INFO_PROCESS_V2
。更改
ZX_INFO_PROCESS
和zx_info_process_t
别名以引用 v2 主题和结构体。等待之前的更改全面发布。
更新所有代码(树内和树外代码)以再次使用
ZX_INFO_PROCESS
。移除 v1 主题和结构体,以及 v2 别名。
这些类型的 Rust 和 Go 版本也会进行类似的更新。
性能
添加的逻辑产生的运行时成本应该微乎其微,尤其是因为它会在单个进程的生命周期中分摊。
安全注意事项
如果程序已有进程的句柄,则它可以执行和收集的内容,远远超出该进程启动的时间。此外,许多其他操作系统中已经暴露了开始时间,这似乎也无需担心。
隐私注意事项
请参阅上文的安全注意事项。
测试
Zircon 的进程相关核心测试将进行扩展,以断言某些原因,例如在 zx_process_start()
之前和之后获取的时间样本确实会夹杂记录的开始时间,并且尚未启动的进程未设置 ZX_INFO_PROCESS_FLAG_STARTED
。
文档
ZX_INFO_PROCESS
文档将相应地更新。
缺点、替代方案和问题
此外,他还考虑将“启动”时间公开为一个更宽泛的任务级概念(例如在 ZX_INFO_TASK_RUNTIME
下公开)。对于线程而言,内容以相同的方式扩展:线程的开始时间是调用 zx_thread_start()
的时间点。对于作业,最自然地是说其在第一个子项启动时“启动”。但是,由于作业可以嵌套,因此会引入遍历任务子树,与处理其他两种任务类型相比,该逻辑相对复杂。最终,我们决定放弃这些扩展,因为它们无法满足当前需求,并且可让我们回避任务层次结构遍历的需求。
现有艺术和参考资料
Linux:/proc/[pid]/stat
提供 starttime
。FreeBSD:/proc/[pid]/status
以空格分隔的统计信息列表中显示开始时间。
macOS:proc_pidinfo()
系统调用似乎会公开此时间。