RFC-0237:使用 ZX_CLOCK_UPDATED 发送时钟更新信号

RFC-0237:使用 ZX_CLOCK_UPDATED 信号时钟更新
状态已接受
区域
  • 内核
说明

添加了在更新 Zircon 时钟时发送的新类型信号

Gerrit 更改
作者
审核人
提交日期(年-月-日)2023-09-26
审核日期(年-月-日)2024-01-03

摘要

此 RFC 提议向 Zircon 时钟引入新的时钟信号 ZX_CLOCK_UPDATED,该信号会在时钟每次更新时闪烁。

设计初衷

时钟单调时钟参考时间轴的一维线性转换,用于定义“参考”时间(即设备的单调时钟)应如何转换为时钟输出的“合成”时间。因此,UTC 时钟是一种不断调整的转换,当应用于设备单调时钟的当前值时,会生成当前 UTC 时间。

Zircon 中 UTC 时钟的仿射转换仅由 Timekeeper 使用系统调用 zx_clock_update 进行更新,并且可以由任何时钟用户使用系统调用 zx_clock_get_details 进行读取。

为了让在 Starnix 上运行的 Linux 程序能够使用 vDSO 函数 clock_gettimegettimeofday 计算世界协调时间 (UTC),Starnix vDSO 必须能够访问从单调时间到 UTC 时间的最新时钟转换。目前,Starnix 内核能够通过使用 zx_clock_get_details 定期轮询 Zircon UTC 时钟以获取时钟转换,然后将此转换加载到 Starnix 内核和 Starnix 上运行的 Linux 程序的用户空间共享的内存页面中,从而提供此访问权限。

脉冲是指对信号进行无限快速的断言和取消断言。这意味着,等待时钟信号发生变化的观察器可以检测到脉冲,但任何观察器都不会读取要断言的时钟信号的值。通过引入 ZX_CLOCK_UPDATED(一种在时钟更新时闪烁的时钟信号),Starnix 内核可以改为收到 UTC 时钟更新的通知,并从 Zircon 获取最新的转换,然后在收到这些通知后立即更新 Linux 程序使用的时钟转换。这会缩短 Zircon 中时钟转换发生变化与 Linux 程序计算 UTC 时间时使用此新转换之间的潜在延迟时间。

利益相关方

哪些人对此 RFC 的接受与否有利益相关?(此部分为可选部分,但建议填写。)

教员

  • cpu@google.com

Reviewers:

  • abarth@google.com
  • maniscalco@google.com
  • johngro@google.com

咨询了

  • mariagl@google.com
  • fdurso@google.com
  • qsr@google.com

社交

已与上述所有审核员和顾问进行过讨论。此文档之前有一个设计文档,并已收到所有利益相关方的非正式反馈。

本文档中的信息已根据需要纳入到本 RFC 中。

设计

Zircon 时钟包含一个信号:ZX_CLOCK_STARTED,该信号会在时钟启动时有效。该设计添加了一个新的时钟信号 ZX_CLOCK_UPDATED,该信号会在每次更新时钟时进行突发。

为了能够对信号进行闪烁,该设计还涉及修改目前用于更新 Zircon 信号的 Dispatcher::UpdateState。目前,该函数接受两个输入:set_maskclear_mask,它们用于指定要设置(断言)和清除(取消断言)的信号。除了更新 set_maskclear_mask 指定的信号之外,该函数还会使用 NotifyObservers 函数通知所有观察器哪些信号从非活跃状态转换为活跃状态。

修改内容是向 UpdateState 添加第三个输入(默认为零),并将其命名为 strobe_mask。这会指定要闪烁的所有信号。指定为闪烁的信号不会更改值,但修改了 NotifyObservers 调用,以便还会通知所有观察器 strobe_mask 指定的任何信号,以便观察器知道信号已更新。

为了使用此信号以防止用户错过更新,以便用户能够及时了解时钟转换的更新,用户不应使用 zx_object_wait_onezx_object_wait_many 等待信号闪烁。如果用户读取当前时钟详细信息,然后调用 zx_object_wait_one 以等待时钟更新,则在读取当前时钟详细信息和调用等待操作之间,时钟可能已由 Zircon 更新,因此系统不会注册此更新。

而应改用 zx_object_wait_async。在读取当前转换之前,用户应针对时钟发布异步等待。然后,在读取时钟详细信息后,用户可以在发送异步等待的端口上等待。这样可以防止错过对时钟详细信息的更新。

这种机制的结果是,如果在创建异步等待和读取时钟详细信息之间更新了时钟,则会导致在端口上等待时立即唤醒,即使读取的时钟转换是最新的也是如此。未来的工作可能会改进此信号,以消除这些虚假唤醒的可能性。

实现

此设计可以在一个小 CL 中实现。CL 会定义新信号并修改 UpdateState 以添加新的 strobe_mask 输入。

性能

Starnix 内核将使用以下新信号来减少在 Starnix 上运行的 Linux 程序的 UTC 时钟的潜在错误。

目前,Starnix 是此信号的唯一提议用户,但将来可能会有其他用户使用此信号(例如,为了支持 C++ 标准库能够在 UTC 截止期限之前阻塞线程,而实现的 C++ 运行时)。使用 UpdateState 对信号进行闪烁的时间复杂度与信号的观察器数量成线性关系。这意味着,当 ZX_CLOCK_UPDATED 的观察器数量变大时,就会出现性能问题。

向后兼容性

任何现有信号的行为都不会发生变化,因此预计不会出现向后兼容性问题。

安全注意事项

此提案预计不会产生任何安全影响。

隐私注意事项

我们预计此提案不会产生任何隐私影响。

测试

我们将添加一些测试来验证设计中指定的行为。这些测试将确保时钟的任何用户都无法手动更改信号,时钟更新时,等待时钟 ZX_CLOCK_UPDATED 信号上的频闪的所有观察器都会收到通知,并且在没有时钟更新时,信号的观察器不会收到通知(这意味着,在没有时钟更新时,永远不会断言 ZX_CLOCK_UPDATED)。

文档

以下文档将更新为介绍 ZX_CLOCK_UPDATED,以及用户在使用此信号时应遵循的方法时钟,以免错过更新。

缺点和替代方案

缺点

本文档的性能部分介绍了随着信号观察器数量的增加而导致性能下降的问题。如果时钟信号的观察器数量增加到很大的数量,则可能需要进一步采取措施来缓解这些性能问题。

替代方案

针对动机提出的问题,另一种解决方案是将 Zircon UTC 时钟的时钟详细信息直接映射到 Starnix 内核。然后,Starnix 内核可以将此内存直接映射到 Linux 进程的空间。这意味着,对 Zircon 中时钟对象的任何更新都会立即传播到 Starnix 和 Linux 进程。这样一来,就无需引入新信号,并且不会减少传播到 Starnix 的时钟更新延迟时间,而是会完全消除此延迟时间。不过,这需要对 Zircon 内核进行大幅更改。