姓名
clock - 用于跟踪时间进度的内核对象。
概要
时钟是单调时钟参考时间轴的一维线性转换,可由时钟维护者以原子方式进行调整,并由客户端观察。
说明
属性
时钟的属性是在创建时钟时确定的,之后便无法更改。目前,定义了三个时钟属性。
ZX_CLOCK_OPT_MONOTONIC
设置后,时钟保证具有单调行为。也就是说,对时钟的任何观察序列都保证会产生一个时间序列,该序列始终大于或等于之前的观察结果。单调时钟从不会向后跳转,但可以向前跳转。正式:
给定时钟 C,设 C(x) 为从参考时间轴 C 的时间轴映射的函数。C(x) 是一个分段线性函数,由 C 的维护者确定的所有时间段内的所有线性转换片段组成。当且仅当满足以下条件时,C 才是单调函数:
对于所有 R1、R2:R2 >= R1
C(R2) >= C(R1)
ZX_CLOCK_OPT_CONTINUOUS
设置后,时钟保证会持续运行。也就是说,对时钟转换的任何更新都保证与上一个转换片段具有第一阶连续性。正式:
设 Ci(x) 为 C(x) 的 i 个仿射转换片段。设 Ri 为参考时间轴上第一个定义了 Ci(x) 的时间点。时钟 C 连续的充分必要条件是:对于所有 i
Ci(Ri + 1) = Ci + 1(Ri + 1)
后备时间
时钟的后备时间表示时钟可以设置的最小值。由于时钟只能向前跳动,而不能向后跳动,因此时钟的观察器永远不可能收到低于时钟创建者配置的后备时间的值。
在创建时,可以通过 zx_create_args_v1_t
结构提供回退时间。否则,将默认为 0。
在时钟更新操作期间,如果尝试将时钟的值设置为小于后备时间的值,则会失败并抛出 ZX_ERR_INVALID_ARGS。未在初始设置时设置的时钟始终会报告为时钟配置的后备时间。返回顶部的时长不得低于默认值零。
隐含属性
- 系统中所有时钟对象的参考时钟都是单调时钟。
- 所有时钟对象的标称单位均指定为纳秒。此属性不可配置。
- 所有时钟对象的频率调整单位均指定为百万分之一,即 PPM。
- 时钟对象的频率调整允许的最大范围被指定为 [-1000, +1000] PPM。此属性不可配置。
其他制作选项
ZX_CLOCK_OPT_AUTO_START
在创建时钟时使用此选项时,时钟会从已启动状态开始,而不是默认的未启动状态。如需了解详情,请参阅启动时钟。
读取时钟
给定时钟句柄后,用户可以使用 zx_clock_read()
系统调用查询该时钟给出的当前时间。时钟会读取 ZX_RIGHT_READ 权限。保证所有观察器的计时器读取结果是一致的。也就是说,如果两个观察者在完全相同的参考时间 R 查询时钟,他们将始终看到相同的值 C(R)。
参考时间表、zx_ticks_get()
和 zx_clock_get_monotonic()
如前所述,zx_clock_get_monotonic() 是所有用户创建的 Zircon 时钟的参考时间轴。这意味着,如果用户知道时钟实例的当前转换,那么给定时钟实例时间轴上的值,可以计算时钟单调时间轴上的相应点(反之亦然)。这也意味着,如果未对内核时钟进行速率调整,时钟单调和内核时钟将以完全相同的速率滴答。
除了时钟单调时间轴之外,zircon 内核还通过 zx_ticks_get()
和 zx_ticks_per_second()
公开“滴答”时间轴。在内部,计数实际上是时钟单调的参考时间轴,并且会直接从可供内核访问的架构适用计时器单元读取。时钟单调实际上是对以纳秒单位归一化的计数器时间轴的线性转换。两个时间轴都会在内核启动时从零开始计时。
由于时钟单调性是基于滴答的静态转换,并且所有内核时钟都是基于时钟单调性的转换,因此除了时钟单调性之外,滴答还可以用作内核时钟的参考时钟。
提取时钟的详细信息
除了简单读取时钟的当前值之外,拥有 ZX_RIGHT_READ 权限的高级用户还可以使用 zx_clock_get_details()
读取时钟并在过程中获取详细信息。调用成功后,返回给调用方的详细信息结构将包含:
- 当前时钟单调到时钟转换。
- 当前的秒针到时钟转换。
- 时钟的当前对称误差边界估算值(如果有)。
- 时钟上次更新的时间,由时钟单调参考时间轴定义。
- 对系统滴答计数器的观察,是在观察时钟期间进行的。
- 在创建时定义的时钟的所有静态属性。
- 每次更新时钟的底层转换时,其值都会发生变化的生成 Nonce。
高级用户不仅可以使用这些详细信息计算时钟的近期 now
值(通过使用“ticks-to-clock”转换来转换报告的“ticks-now”观察结果,这两项均由“get details”操作报告),还可以:
- 了解自上次
zx_clock_get_details()
操作(使用生成 Nonce)后时钟转换是否发生了更改。请注意,时钟的生成 Nonce 不保证从任何给定值开始,也不保证在每次更新时以任何特定方式(例如按固定值递增)进行更改。相反,在每次更新时,生成 Nonce 都会更改为一个值,该值保证不同于更新前立即拥有的值。 - 将时钟转换与其他时钟的转换组合,以推理两个时钟之间的关系。
- 了解时钟维护者对误差边界的最佳估算值。
- 根据上次校正时间、当前转换和时钟的最大允许校正系数,推理时钟相对于参考时钟的可能未来值的范围(请参阅上文“隐含属性”部分中所述的频率调整的最大允许范围)。
启动时钟和时钟信号
创建后,计时器尚未开始。所有尝试读取时钟的操作都会返回时钟的配置后备时间,如果在创建时未指定,则默认为 0。
在时钟的维护者执行首次更新操作(必须包含设置值操作)后,时钟便会开始运行。时钟将在此时开始运行,其速率等于参考时钟加上维护者指定的与标称值的偏差。
时钟还有一个 ZX_CLOCK_STARTED 信号,用户可以使用该信号来了解时钟何时实际启动。最初,此信号未设置,但在首次成功执行更新操作后会设置。一旦启动,时钟就不会停止,并且 ZX_CLOCK_STARTED 信号始终会被断言。
最初,时钟是单调时钟的克隆,这使得单调时钟时间轴和合成时间轴之间的转换成为恒等函数。此时钟在创建后可能仍会维护,具体取决于权限、ZX_CLOCK_OPT_MONOTONIC 和 ZX_CLOCK_OPT_CONTINUOUS 属性以及配置的后备时间所施加的限制。
如果使用 ZX_CLOCK_OPT_AUTO_START 选项创建时钟,则无法将其配置为具有大于当前时钟单调时间的回退时间。如果允许这样做,则会导致时钟的当前时间被设为其回跳时间之前的时间。
维护时钟
拥有时钟对象的 ZX_RIGHT_WRITE 权限的用户可以使用 zx_clock_update()
系统调用充当时钟的维护者。在每次调用 zx_clock_update()
时,都可以调整时钟的三个参数,但每次都不需要调整这三个参数。这些值如下:
- 时钟的绝对值。
- 时钟的频率调整(与标称值的偏差,以 ppm 表示)
- 时钟的绝对误差边界估算值(以纳秒为单位)
对时钟转换的更改会在系统调用本身期间发生。用户可能无法指定调整的具体参考时间。
对设置了 ZX_CLOCK_OPT_MONOTONIC 属性且会导致非单调行为的时钟的绝对值所做的任何更改都会失败,并返回 ZX_ERR_INVALID_ARGS 代码。
第一个更新操作会启动计时器,并且必须包含设置值操作。
除了首次设置值操作外,所有尝试设置已设置 ZX_CLOCK_OPT_CONTINUOUS 属性的时钟的绝对值的操作都会失败,并返回 ZX_ERR_INVALID_ARGS
关于时钟误差边界估算值的说明
zx_clock_get_details()
系统调用可向用户提供有关时钟的许多精细详细信息,包括“误差边界估算值”。此值以纳秒为单位,表示时钟维护人员当前对时钟相对于维护人员使用的参考时钟的误差的最佳估算值。例如,如果用户提取的时间 X
的误差边界估计值为 E
,则时钟维护者尝试表明,它认为时钟的实际值位于 [ X-E, X+E ]
范围内。
内核 API 未指定此估算值的置信度。有些时钟维护者可能使用严格的边界,有些则使用无法证明但提供“高可信度”的边界,而有些可能对其估算结果仍不太有信心或完全没有信心。
如果用户需要了解其访问的错误估算值的客观质量(例如,强制执行证书有效日期或 DRM 许可到期),则应了解系统中哪个组件在维护其时钟,以及维护者在其发布的错误边界估算值的置信度方面提供了哪些保证。
SYSCALLS
- 时钟转换
zx_clock_create()
- 创建时钟zx_clock_read()
- 读取时钟时间zx_clock_get_details()
- 提取时钟与单调时钟之间的关系的详细信息zx_clock_update()
- 调整时钟与时钟单调引用的当前关系。