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 内核能够通过以下方式提供此访问权限:定期轮询 Zircon UTC 时钟以获取时钟转换,使用 zx_clock_get_details,然后将此转换加载到 Starnix 内核和在 Starnix 上运行的 Linux 程序的用户空间共享的内存页面中。

频闪信号是指信号的断言和取消断言速度极快。这意味着,等待时钟信号发生变化的观测者可以检测到选通信号,但没有任何观测者会读取时钟信号的断言值。通过引入 ZX_CLOCK_UPDATED(一种在时钟更新时闪烁的时钟信号),Starnix 内核可以改为在收到 UTC 时钟更新通知后,立即从 Zircon 获取最新的转换,然后更新 Linux 程序使用的时钟转换。这样可以减少 Zircon 中时钟转换发生变化与 Linux 程序计算 UTC 时间时使用此新转换之间的潜在延迟。

利益相关方

哪些人会受到此 RFC 是否被接受的影响?(此部分为可选,但建议填写。)

辅导员

  • cpu@google.com

审核者

  • 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++ 运行时的实现,以便支持 C++ 标准库在 UTC 截止时间之前阻塞线程的能力)。使用 UpdateState 对信号进行频闪的时间复杂度与信号的观测者数量呈线性关系。这意味着,当 ZX_CLOCK_UPDATED 的观察者数量变多时,就会出现性能问题。

向后兼容性

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

安全注意事项

预计此提案不会带来任何安全方面的影响。

隐私注意事项

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

测试

我们将添加测试来验证设计中指定的行为。这些测试将确保时钟的任何用户都无法手动更改信号,确保任何等待时钟 ZX_CLOCK_UPDATED 信号频闪的观测者在时钟更新时收到通知,并且确保在时钟未更新时(即在未更新时 ZX_CLOCK_UPDATED 从不被断言)不会通知信号的观测者。

文档

我们将更新以下文档,以说明 ZX_CLOCK_UPDATED,以及使用此信号时用户应遵循的方法时钟,以免错过更新。

缺点和替代方案

缺点

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

替代方案

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