Skip to content

[Feature] 时间子系统调研:设时一致性、clock 语义与计时连续性问题及统一时间维护建议 #11927

Open

Description

@dongly

RT-Thread Version: master a59e72fb5c
Affected area: Other / Not sure(横跨内核 clock、components/drivers/rtc 与 clock_time、components/libc、RT-Smart VDSO、PM)


速览

项目 要点
问题 tick/clock_time/RTC/libc/VDSO 各维护时间基线,读取路径可能不一致,部分 API 名不符实
已有基础 调度 tick、clock_time source/event 抽象、RTC 框架、VDSO offset、PM tickless 补 tick
关键不足 10 项,见 3.8(设时不统一、clockid 语义混乱、软 RTC 假同步、回绕/溢出、hrtimer 回退、PM 分叉、启动授时状态/发布缺口、NTP 版本边界)
目标 统一 timekeeper + 单一设时入口 + clockid 语义契约 + 授时方向仲裁
路径 五步:接口一致(P0) → 最小 timekeeper(P1) → 授时与 PM 边界(P1,普通 MCU 终点) → 平台高精度(P2) → 高级能力(P2)
裁剪 语义契约/错误码/兼容性不可裁;微秒 source/slew/PTP/VDSO/tickless 按需
边界 基线 a59e72f,静态分析,未编译未上板;核查日期 2026-10-24

详细导航:现状 §3 · 工作项 §1.1 · OS 对比 §4 · 目标 §5 · 实施 §6 · 验证 §7

1. 范围与结论

本文梳理 RT-Thread 调度时间、日历时间、RTC 和 NTP 的关系,参考其他 OS 提出理顺方向。

  • 基线:master 提交 a59e72fb5c;行号对应该基线。外部参考为在线 master/latest(核查日期 2026-10-24),未固定发行版。
  • 验证:源码静态检查;无编译、上板、休眠、回绕或 VDSO 复现。
  • 本文是调研与设计建议,不代表已实现全部 POSIX/Linux 时钟语义。

核心结论:并非缺少时间基础设施,而是各子系统间缺少统一的时间维护协议。先解决语义和一致性,再完善对时策略。

1.1 问题速览与工作项

下表将本文结论组织为 A–F 六项可跟踪的工作项。各问题的触发条件、影响与边界以第 3 节对应小节为准;表中范围与验收为摘要,完整内容见第 6 节对应实施步骤。A–F 不按文档顺序实现,满足依赖即可并行。P2 项按平台/产品需要启动;普通 MCU 走完 A–D 即达阶段性终点(6.1)。验收以第 6 节对应步骤为准;被裁剪项标注"不适用"。

工作项 优先级 范围(摘要) 验收(摘要) 依赖 证据与详情
A. 统一设时与 clock 语义 P0 所有设时入口接入同一更新协议并同步 VDSO;clockid 能力矩阵与明确错误行为,未实现类型明确拒绝 各读取路径一致;能力可查询 无,可最先启动 3.8.1–3.8.3;第 6 节第 1 步
B. 最小 timekeeper 与软 RTC 修复 P1 提取"日历基线 + 单调计数经过"的最小日历核心;修复软 RTC 自读自写与亚秒丢弃 读取与 RTC 设备解耦一致;走时连续、未授时可查 A 3.8.4、3.8.5、5.1;第 6 节第 2 步
C. RTC 能力矩阵与兼容 P1 秒/timeval/timespec/resolution 驱动能力矩阵,统一兼容回退或明确不支持 矩阵可查询,分辨率报告与实际能力一致 可与 A 合并设计 3.8.2;第 6 节第 1 步
D. 授时状态与低功耗边界 P1 统一启动授时与发布流程;对时统一入口;同步方向仲裁(可信等级决定 RTC 与系统谁跟谁);逐电源模式确认 source 停走、event 唤醒与补偿归属 各电源模式不漏计不重计;统一发布流程;无方向振荡 A、B 3.8.8–3.8.10、5.5、5.6;第 6 节第 3 步
E. 平台高精度按需 P2 选定平台接入自由运行 source 与独立 event;回绕扩展与 deadline 范围;回调契约 以真实事件链与延迟测量验收,实际后端可查询 A;与 B–D 可并行,按平台需要启动 3.8.5–3.8.7、5.3 第一阶段;第 6 节第 4 步
F. 对时增强与高级能力按需 P2 slew/校频与 RAW 区分;RTC 受控回写;统一事件仲裁与 tickless 独立参考源实测达到产品自定目标;仲裁不破坏既有回调契约 B、D 3.8.10、5.3 第二阶段;第 6 节第 5 步

2. 先区分四种角色

角色 解决的问题 不应混用的场景
调度 tick 时间片、内核超时、软定时器 不能直接当作 Unix 日历时间
单调时间与 boottime 测量间隔、运行时计时,以及按约定是否计入 suspend 不应被设置日历时间的 step 污染
系统日历时间 REALTIME 当前日期、日志时间戳、网络协议中的时刻 可能跳变,不宜直接用于相对超时
RTC 与 NTP RTC 提供持久授时;NTP 提供外部时间校准 都不应各自绕过统一入口维护一份互不一致的系统时间

时区仅用于日历解释和显示。UTC、POSIX 时间戳与 TAI 是不同概念:UTC 存在闰秒,POSIX 秒数不逐一计入闰秒,不能将 UTC 定义为“没有闰秒的时间”。

3. 当前 RT-Thread 实现

3.1 调度 tick

src/clock.c 提供 rt_tick_get()、rt_tick_increase()、rt_tick_increase_tick()、rt_tick_get_delta() 和毫秒换算接口。

  • BSP 时钟中断推进 tick,驱动时间片和 src/timer.c 的定时器检查。
  • rt_tick_increase_tick() 支持批量补偿 tick。
  • tick 的位宽、回绕和换算精度需要按配置考虑。
  • 现有 rt_tick_set() 不应作为日历校时接口;直接修改调度 tick 可能影响超时逻辑。

3.2 clock_time 与运行时间

主要代码位于 components/drivers/clock_time/:

文件 职责
clock_time_core.c 可替换计数源、频率与分辨率等接口;默认源是 tick
clock_boottime.c 将源 counter 换算为运行时间
clock_hrtimer.c 高精度定时与延时支持,实际精度取决于配置和源能力
clock_timer.c 定时事件设备相关支持

不能仅因启用 RT_USING_CLOCK_TIME 就承诺高精度、长期严格单调或完整 suspend 语义:默认源仍为 tick;将窄计数器转换成 64 位不等于自动完成回绕扩展。

3.3 RTC 框架与软 RTC

RTC 框架位于 components/drivers/rtc/,主要包括 dev_rtc.c、dev_soft_rtc.c、dev_alarm.c,以及多个具体 RTC 驱动。

  • 通用 libc 主要通过名为 rtc 的设备访问日历时间。
  • 设备可能是软 RTC、片内 RTC、MMIO RTC 或 I²C RTC,不能概括为每次读取都访问 I²C。
  • set_date()、set_time() 涉及本地日历转换;时间戳接口与时区转换应分开理解。
  • 声明了某个 RTC 控制命令,不等于所有驱动都实现该命令。

软 RTC 已采用"日历基线 + 运行时间增量"外推结构,但周期同步实现不能称为纠漂:

  • rt_soft_rtc_sync()(359–372):自读整数秒,以零小数重设基线——同源自读自写,无法估计频率误差,丢弃亚秒还可能回退。
  • rt_soft_rtc_set_source()(399–407):仅检查设备存在,未保存或读取指定源。
  • RT_USING_SYSTEM_WORKQUEUE 是编译条件,不自动启动同步任务。

3.4 libc 时钟接口及配置差异

主要实现:components/libc/compilers/common/ctime.c。

接口或配置 本地基线行为
time() 无 RT_USING_RTC 通用弱实现返回 (time_t)-1,见 351–369
gettimeofday() 通过 RTC 读取,具有 timeval 到秒的回退;无 RTC 时失败
POSIX clock 实现 受 RT_USING_POSIX_CLOCK && RT_USING_CLOCK_TIME 控制,见 657–1014
REALTIME / REALTIME_COARSE,有 RTC 请求 RTC GET_TIMESPEC,没有与 gettimeofday 相同的秒级回退
REALTIME / REALTIME_COARSE,无 RTC 在所查实现中落入 boottime 分支;不代表获得可信日历时间
MONOTONIC / RAW / COARSE / BOOTTIME 当前均映射到同一 boottime,见 842–858
PROCESS / THREAD CPU clock 当前也返回 boottime,代码标注 TODO,不是真正 CPU 消耗时间

旧 RTC 框架控制分发 dev_rtc.c:55–90 不处理 TIMESPEC/TIMERES。因此可能出现同一设备上 time() 和 gettimeofday() 成功,而 clock_gettime(CLOCK_REALTIME) 失败的情况。

3.5 Smart VDSO 与设时一致性

components/lwp/arch/common/vdso_kernel.c:176–217 已维护 realtime offset;用户快路径可以直接根据共享时间数据和计数器外推 REALTIME,不必每次读取 RTC。

目前设时路径未统一:

入口 RTC 写入 对应 VDSO 通知
settimeofday() 有 有
clock_settime() 有 有
stime() 有 未见对应通知
set_timestamp() 有 未见对应通知

证据:ctime.c:379–389、569–589、952–956;dev_rtc.c:238–250。

在 Smart/VDSO 快路径有效时,绕过通知的设时操作可能使 RTC 读取和用户态快路径读取不一致。这是静态发现,仍需运行复现。

3.6 低功耗与补偿

components/drivers/pm/pm.c:444–470 已有 tickless 补偿(低功耗计时器测量,恢复后 rt_tick_increase_tick() 补 tick),不能说没有低功耗补偿。

待明确:独立 source 低功耗期间是否停走;tick 补偿是否覆盖该 source;MONOTONIC/BOOTTIME 的 suspend 语义区分;持续运行 source 与额外 sleep offset 的重复计时。

Linux 参考:MONOTONIC 排除 suspend,BOOTTIME 包含 suspend;tickless idle ≠ 系统 suspend。

3.7 NTP 与 lwIP SNTP

主仓 RTC 框架不承担完整 NTP 客户端职责。所查在线 netutils/ntp/ntp.c 中:

  • 使用服务器 transmit timestamp 获取时间,未见完整四时间戳 offset/delay 计算和多样本统计过滤。
  • ntp_sync_to_rtc() 在较新分支直接执行 RTC SET_TIME,旧分支调用 set_time()/set_date(),并非统一通过 settimeofday()。
  • 所查实现为整数秒 step,未见 slew;直接写 RTC 也可能绕过 VDSO 通知。

上述结论仅针对所查在线版本,项目实际 netutils 版本仍需确认。

lwIP 有 SNTP 源码和可覆盖设时钩子,但所查 2.1.2/2.2.1 SConscript 定义了源码列表却未加入最终 src;默认 SNTP_SET_SYSTEM_TIME 可为空操作。不能断言"已编入"或"无人接线",需检查目标工程构建、宏覆盖与 sntp_init() 调用。

3.8 当前实现的不足:触发条件、影响与验收

以下分析基于本文代码基线,没有运行复现或上板验证。"静态确认"指源码路径或实现边界明确,不表示所有 BSP 都会触发。应区分接口缺陷、条件性风险与可选架构能力,不能将尚未采用完整 timekeeper 等同于系统不可用。各项验收标准统一由第 6 节对应实施步骤承载(对应关系见各步骤标题括号)。

3.8.1 系统设时入口不统一,RTC 与 VDSO 可能形成两份日历状态

  • 触发与影响:stime() 直接写 RTC 秒(ctime.c:379–390),settimeofday()、clock_settime() 成功后才更新 VDSO offset(ctime.c:569–592、952–957),所查 netutils 也直接写 RTC。当 Smart/VDSO 已启用且先经受支持入口建立有效 REALTIME 快路径,随后经未通知 VDSO 的入口改时,设备时间已变而用户快路径继续外推旧 offset,同一业务从 time()、gettimeofday()、系统调用和 VDSO 读取时间可能观察到不一致。
  • 边界:静态调用链确认的风险,未运行复现;未启用 VDSO 的系统不触发。直接设置某个 RTC 设备不一定应修改系统时间,关键是明确设备操作与系统设时的接口契约。

3.8.2 RTC 命令支持不一致,基础取时成功不代表 POSIX clock 可用

  • 触发与影响:启用 POSIX clock 与 clock_time、且选用仍经旧框架分发命令的 RTC 驱动时——旧框架 dev_rtc.c:55–93 只分发秒、timeval 和 alarm 命令,不处理 TIMESPEC/TIMERES——gettimeofday() 有 timeval 到秒的回退,而 clock_gettime(CLOCK_REALTIME)、clock_settime()、clock_getres() 分别依赖 TIMESPEC/TIMERES、无等价通用兼容路径(ctime.c:807、847、952)。同一设备可能让 time()、gettimeofday() 成功,却让 clock_gettime(CLOCK_REALTIME) 或 clock_getres() 失败;应用仅验证 shell 日期或秒级取时,不能证明 POSIX 接口已正确接入。
  • 边界:不能扩展为"所有硬 RTC 都不支持高精度接口";软 RTC、自定义 control 和不同 DM 驱动须分别检查;timespec 转换只兼容数据格式,不能凭空增加硬件精度。

3.8.3 时钟名称多于实际语义,应用难以选择正确时间域

  • 触发与影响:ctime.c:842–858 将 MONOTONIC、RAW、COARSE、BOOTTIME 及 PROCESS/THREAD CPU clock 全部映射到同一 boottime(源码保留 TODO);未启用 RTC 时 REALTIME 分支还落入 boottime,启用了 RTC 但没有设备时则可能失败。CPU clock 无法据此统计线程或进程实际占用 CPU 的时间,BOOTTIME 与 MONOTONIC 没有独立的 suspend 语义,无 RTC 的某些配置把启动经过时间当作日历时间返回,应用可能误将小的 epoch 数值用于证书、日志和协议时间戳。
  • 同类缺陷:clock_nanosleep() 相对模式(未置 TIMER_ABSTIME)无论 clockid 恒返回 -RT_EINVAL——ctime.c:869–907 中 err 初始化为 -RT_EINVAL,仅 ABSTIME 分支赋值取时结果,合法相对睡眠请求无法到达后面的相对 nanosleep() 分支。
  • 边界:未校频时 RAW 与 MONOTONIC 数值相同、COARSE 与普通版本相同本身不违规;真正问题是缺少清晰能力声明,以及 CPU 时间、日历时间等不同语义被静默替代。

3.8.4 软 RTC 的“同步”没有消费外部源,还会丢弃亚秒

  • 触发与影响:rt_soft_rtc_set_source(name) 仅检查设备存在,没有保存该源并读取它(dev_soft_rtc.c:399–407);周期 work 继续调用的 sync 函数从软 RTC 自身读取整数秒,再以零纳秒重设基线(dev_soft_rtc.c:359–373)。指定源的名字不等于真正接入了该源,同源自读自写无法识别晶振频率误差;重设时丢掉原有小数秒,存在回退与相位扰动风险,不能将周期执行成功作为“已纠漂”的证据。
  • 边界:启用 workqueue 宏不等于周期任务自动启动;默认软 RTC 仍能按基线 + elapsed 提供时间,不能把同步逻辑问题泛化为整个软 RTC 不工作。

3.8.5 64 位接口不等于长期连续计时,hrtimer 还有独立半圈限制

  • 问题一(source 回绕):默认 source 将 rt_tick_get() 作为 counter,窄位宽 source 未扩展就回绕时,运行时间可能随之回绕(clock_boottime.c 不替所有后端提供通用回绕扩展),属长期取时问题。
  • 问题二(hrtimer 半圈):32 位平台 clock_hrtimer.c 的队列计数使用 unsigned long,经有符号差比较并限制单次 delay 小于半圈——即使 source 已正确扩展为 64 位,同源同频 1 MHz 下单次 delay 上限约 35.8 分钟,超限不能作为普通合法请求直接传入。
  • 问题三(换算中间值溢出):clock_boottime.c 与 clock_time_core.c 按 (cnt * res) / RT_CLOCK_TIME_RESMUL 换算,乘法在 64 位无符号整数内完成,除法不能挽救此前的溢出;以 1 MHz(res=10⁹,RESMUL=10⁶)为例,counter 约 18446 秒(约 5.1 小时)时中间乘积首次溢出,运行时间骤降——远早于 64 位 source 自身回绕,"64 位回绕扩展 + 现有换算"不足以闭环长期连续计时。
  • 边界:按实际 source 位宽、频率、扩展方式和平台字长判断,不能声称所有后端同一时长失效;计数分辨率不是回调最坏延迟保证;高层延时 API 参数范围(如 32 位平台纳秒参数)独立受限,各层需分别验证。

3.8.6 事件后端选择与静默回退,使“启用 hrtimer”不等于高精度生效

  • 触发与影响:clock_time_core.c:101–109 自动选择首个符合条件的 source/event(clock_timer.c 另有桥接 owner),clock_hrtimer.c:87–125 的默认实现先尝试硬件 event、失败再静默转换为 tick 定时器 shrtimer,且部分 BSP 会覆盖 weak 接口,不能只检查通用注册路径。仅打开 RT_USING_CLOCK_TIME,或拥有高频 SOURCE-only 设备,都不能证明定时事件已脱离 tick 粒度;多设备注册时初始化顺序可能影响默认选择,指定硬件存在但 probe 失败也可能让系统仍能运行,却不满足精度要求。
  • 边界:tick 回退是有价值的兼容机制,不是 bug;Rockchip 等 BSP 有专用硬件路径,STM32 已有 drv_tim.c EVENT 基础,不能概括为“都没有硬事件”。

3.8.6.1 BSP drv_tim.c 与时间架构的分工

BSP 的定时器驱动(如 STM32 bsp/stm32/libraries/HAL_Drivers/drivers/drv_tim.c)是硬件桥梁,不是系统时间本身:

  • BSP 驱动负责:初始化 TIM 时钟/分频/计数模式,管理 CCR/ARR/中断,清除中断标志,调用框架 ISR 入口,暴露设备操作与能力;不直接维护日历时间,也不绕过统一入口修改系统时间。
  • 时间架构负责:选择默认 source/event,将硬件计数解释为运行时间,维护 MONOTONIC/BOOTTIME/REALTIME,管理 hrtimer deadline 队列,决定授时、回写、VDSO 更新与低功耗补偿,保证同一事件资源不被多个 owner 同时重编程。

drv_tim.c 已通过 rt_clock_timer_register()/rt_clock_timer_isr() 提供 EVENT 后端基础,因此该类平台已有 EVENT 能力,不是“完全没有 hrtimer 后端”;但“已有 EVENT”不等于“已启用且默认生效”,也不等于“已有连续 SOURCE”。对采用该驱动的目标平台,EVENT 路径可复用/改造,SOURCE(自由运行计数 + 回绕扩展)需新增或独立评估,并需目标板配置与实测验证。该工作对应第 6 节第 4 步(工作项 E),属于平台按需能力,不是普通 MCU 的默认义务。

3.8.7 hrtimer 回调执行约束较强,慢回调会扩大计时路径延迟

  • 触发与影响:到期处理在持锁状态下直接调用 timeout_func(clock_hrtimer.c:232–239 持锁进入,174–204 调用回调),硬件 event 通常从 ISR 进入这条路径;start/stop 重编程时也可能在调用线程内同步执行已到期队列项(clock_hrtimer.c:206–225、261–280),回调因此存在中断与线程双上下文。回调耗时不仅影响自身,还可能延后同队列其他 deadline 的处理,并扩大锁占用和中断受限窗口;回调内调用可能再次获取相同锁的定时器操作时,需专门检查重入契约,不能默认普通线程中安全的操作在这里同样安全。
  • 边界:执行模型约束与条件性风险,未测量实际延迟,也不意味着回调都应改成线程执行;锁外派发同样需解决对象生命周期、并发 stop 和周期重挂语义。

3.8.8 PM 已补调度 tick,但独立 source 的睡眠连续性尚需单独闭环

  • 触发与影响:pm.c:444–470 已通过低功耗计时器测量并调用 rt_tick_increase_tick() 补偿;若 boottime 仍以 tick 为 source 可间接受益,但换成独立硬件 source 后补 tick 不会自动修复它的 counter 或时间映射——独立 source 深睡停走而恢复后仅补 tick,则调度计时与该 source 派生时间不再对应;source 一直运行却无条件注入睡眠增量,则重复计时。普通 TIM 无法唤醒 STOP 时,精密 deadline 不能仅靠该 event 保证。
  • 边界:source 停走取决于芯片和电源模式;tickless idle ≠ 系统 suspend;MONOTONIC 排除 suspend、BOOTTIME 包含 suspend,不能以“所有时钟都加睡眠时间”统一修复。

3.8.9 启动有时间数值,但缺少统一授时状态与发布流程

  • 触发与影响:硬 RTC 的通用读取路径主要按需访问设备,软 RTC 默认从 2018 年基线外推;VDSO REALTIME 有独立 ready 标志,首次有效设时前回退系统调用,不会仅因 RTC 注册就建立 offset(vdso_kernel.c:59–60、164–218)。应用拿到合法日期却无法判断来源(默认值/RTC 保持/人工/网络同步),读取成功与授时可信混同,业务可能过早校验日期或把未验证时间回写硬 RTC。
  • 边界:VDSO 未 ready 时回退是正确保护,不是返回错误时间;硬 RTC 是否有效、是否保留掉电时间由驱动与硬件决定;统一授时状态是需补充的管理能力,不要求小系统实现复杂同步服务。

3.8.10 对时链路依赖包版本和工程接线,协议与校钟策略尚需分层

  • 触发与影响:所查 netutils 在线版本以服务器 transmit timestamp 的整数秒直接 step 到 RTC,未见完整四时间戳估计、样本过滤或 slew;主仓 lwIP 的 SNTP 源码存在,但所查标准 SConscript 未加入其源列表,默认设时钩子也可能为空。网络往返延迟、服务器异常和亚秒截断可能直接进入设时结果;频繁 step 会使日历时间跳变,而晶振频率误差仍继续积累。仅有包配置或收到响应,不等于系统已经正确校时,更不代表 VDSO、RTC 回写与可信状态均已同步。
  • 边界:netutils 行为仅适用所查在线版本,不代表工程锁定版本;简单 SNTP 在低要求设备上可足够,不必默认引入完整 NTP 守护进程;对时能力取决于实际构建、宏覆盖与调用链,而非文件是否存在。

修复顺序:先 P0 设时与语义(3.8.1–3.8.3)→ 再 P1 最小 timekeeper、基础 source 连续性、授时状态与 PM 边界 → 按需开展 P2 平台高精度及高级对时能力。具体问题与工作项映射见 1.1。

4. 其他 OS 的架构参考

OS 单调与日历时间 RTC 与同步 借鉴点
Linux clocksource、timekeeping、clockevents/hrtimer 分层;REALTIME、MONOTONIC、RAW、BOOTTIME 语义分开 RTC 用于启动授时、按策略回写、休眠边界;用户态同步服务配合内核调时接口 单一时间维护核心;step 与频率校正分开;明确 suspend 语义
NuttX 系统计数与日历基准关联,具备统一 clock 接口和可选 timekeeping/调时能力 启动 RTC 授时、恢复同步;所查 NTP 客户端使用 clock_settime step 内核时间与 RTC 明确衔接;客户端只 step 不等于内核没有 slew 能力
Zephyr uptime 是内核计时基础;POSIX clock 提供日历时间接口;time utilities 支持时标转换与同步辅助 RTC 驱动与 SNTP 查询分开;ENODATA 表示时间不可用,不能推出每次启动都清零 协议查询、时间映射和设备驱动解耦
FreeRTOS 内核主要维护 tick,日历时间由应用集成 coreSNTP 提供协议能力,应用维护时间和 RTC 小系统可用精简时间维护层,不必照搬 Linux 全部复杂度
ThreadX tx_time_get/tx_time_set 提供应用可读写的 tick 计数,不能直接当成严格不可设置的单调钟 日历时间由应用与 RTC 集成;NetX Duo 提供 SNTP 明确 API 契约,不能仅根据 tick 名称推定严格单调

需要注意的语义:

  • Linux MONOTONIC 不受日历 step 影响但可受 NTP 频率校正;RAW 区分未校频时间;CLOCK_TAI 非 1958 起累计秒,也不保证不受人工修改 REALTIME 影响。
  • Linux RTC 回写有条件("11 分钟模式"非无条件保证);FreeRTOS 标准接口是 xTaskGetTickCount() 返回 TickType_t,位宽可配置。

5. 建议的目标架构

以下是演进建议,不是当前实现描述。目标架构分为两条路径:计时路径回答“现在是什么时间”,事件路径负责“何时中断、何时执行”。clock source 与 clock event 是逻辑角色,可以来自同一硬件,也可以由不同硬件提供。

**状态图例(相对本文代码基线):**绿色「已有」表示相关机制存在,不代表所有 BSP 都启用;橙色「需改」表示已有基础但语义或连接需要调整;红色「待增」表示目标中的统一机制尚缺,允许复用现有代码实现;灰色「待验」表示依赖具体 BSP/硬件,尚未验证。图中连线为目标关系,不能因两个节点已有就认定连接已实现。标注可组合使用,如「需改/待验」表示已有基础需调整、且依赖具体 BSP/硬件验证。

flowchart TB
    subgraph TimePath["计时路径"]
        Counter["待验 · 连续硬件 counter"] --> Source["已有 · clock source 抽象"]
        Source --> TK["待增 · 统一 timekeeper"]
        TK --> Mono["需改 · MONOTONIC 语义"]
        TK --> Boot["需改 · BOOTTIME 睡眠语义"]
        TK --> Real["需改 · REALTIME 后端统一"]
        Mono --> API["需改 · 内核取时 / libc / VDSO 一致性"]
        Boot --> API
        Real --> API
        Real --> TZ["已有 · 时区转换 / 日历显示"]
    end

    subgraph SyncPath["授时与持久化"]
        RTC["已有 · RTC 框架 / 硬件驱动"]
        Sync["需改 · 对时与人工设置接入"] --> Set["待增 · 统一校时入口及同步状态"]
    end
    RTC -->|启动授时| Set
    Set --> TK
    TK -->|可信时间按策略回写| RTC

    subgraph EventPath["高精度事件路径"]
        HR["需改 · 已有 hrtimer 队列 / 补时间域联动"] -->|编程最近事件| Event["已有 · clock event 抽象"]
        Event -->|到期中断| ISR["已有 · 到期处理 / 回调"]
        ISR -->|重挂下一事件| HR
    end
    TK -->|当前时间 / deadline 换算| HR

    subgraph TickPath["初期独立调度路径"]
        Periodic["已有 · 独立周期事件 / SysTick"] --> Tick["已有 · OS tick"]
        Tick --> Sched["已有 · 调度 / 时间片"]
        Tick --> Check["已有 · rt_timer_check"]
        Check --> Hard["已有 · rt_timer 硬定时器 / 中断回调"]
        Tick -.->|推进计时基准| SoftThread["已有 · 软件定时器线程 / 按 deadline 等待"]
        SoftThread --> Soft["已有 · rt_timer 软定时器 / 线程回调"]
    end

    PM["需改 · PM 扩展到独立源与事件协调"] -.->|源停走 / 恢复| Source
    PM -.->|睡眠时长补偿| TK
    PM -.->|事件重挂| HR
    PM -.->|调度时间补偿| Tick
    PM -.->|低功耗唤醒配置| RTC

    classDef existing fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
    classDef modify fill:#fff3e0,stroke:#ef6c00,color:#7f3600
    classDef missing fill:#ffebee,stroke:#c62828,color:#8e0000
    classDef verify fill:#f5f5f5,stroke:#616161,color:#212121
    class Source,TZ,RTC,Event,ISR,Periodic,Tick,Sched,Check,Hard,SoftThread,Soft existing
    class Mono,Boot,Real,API,Sync,HR,PM modify
    class TK,Set missing
    class Counter verify
Loading

实线表示主要计时、授时和事件调用关系;虚线表示协调或计时依赖,不表示每个 tick 都唤醒软件定时器线程。RTC 唤醒能力取决于具体硬件。图中 timekeeper 向 hrtimer 提供时间基准,并不表示所有 hrtimer 都使用 REALTIME。软定时器路径需启用 RT_USING_TIMER_SOFT。

图中 hrtimer 与 OS tick 不要求存在上下级关系。初期保留独立 OS tick,hrtimer 不负责推进调度 tick;后续若共享事件硬件,再引入统一 deadline 仲裁。无论是否有到期事件,clock source 都应能保持计时连续性,不能依靠 hrtimer 回调推进系统日历时间。

5.1 职责划分

时间状态所有权

  1. 时间维护层拥有系统日历状态;RTC 是持久授时设备,不是每次读取的唯一载体。
  2. REALTIME 是应用可见的日历时钟语义而非某个 rtc 设备;软 RTC 的基线外推结构可提取为最小 timekeeper 的迁移基础,但不得与 timekeeper 双重维护状态。
  3. 所有设时入口(libc/shell/NTP/驱动)走同一更新协议并同步 VDSO;RTC 设备操作与系统设时需明确区分。
  4. 同步具有可信度状态:区分未授时、RTC 初始化、网络同步、失锁保持、人工设置;RTC 回写由状态与策略决定。

时钟语义

  1. 明确 MONOTONIC/RAW/BOOTTIME/CPU clocks 的支持范围;不支持的类型明确拒绝,不静默伪装。
  2. step、slew 与校频分开:首次授时和大偏差 step,小偏差可渐进修正;MONOTONIC 可调速但不因日历 step 跳变或倒退。

计时与事件

  1. source 提供连续计数,event 编程到期中断;修改事件截止点不应重置共享计数基准。
  2. hrtimer 管理 deadline,不拥有系统时间;相对超时不受日历 step 影响,REALTIME 绝对定时需在日历调整后重新判断。
  3. OS tick 属于调度计时;默认可用 tick 兜底,但独立 source 不应依赖 tick 中断逐次累计;日历校时不得修改调度 tick。

共享与仲裁

  1. 共享事件硬件必须单一仲裁;独立 SysTick 和 TIM 可先并存,统一 tickless 是后续工作。
  2. PM 显式管理睡眠边界:区分 source 停走、suspend 语义、event 唤醒能力。
  3. rt_timer 软/硬定时器(src/timer.c)保留原有 API、tick 单位和上下文语义,不强行替换为 hrtimer:硬定时器沿 tick 中断路径回调,软定时器由专用线程按最近 deadline 等待(非每 tick 扫描),hrtimer 提供更细粒度 deadline 服务。
  4. 当前依赖方向:tick ISR 直接推进 tick 不经 hrtimer;hrtimer 事件不可用时回退 tick 定时器 shrtimer(clock_hrtimer.c:87–124);默认 source 读 rt_tick_get(),方向是 tick→clock_time。
  5. 统一仲裁应合并最近截止时间而非统一所有定时器对象;软定时器线程的等待沿实际调用链去重,事件分发保持既有回调契约。

裁剪原则

  1. 不强制照搬 Linux:小系统先实现统一基线与更新协议,复杂频率驯服可选。

5.2 建议优先级

优先级 工作 原因
P0 统一系统设时入口与 VDSO 更新 先保证不同读取路径看到同一时间
P0 明确 clock API 的配置矩阵、回退和错误行为 避免 API 名称与实际语义不符
P1 核查 source 回绕、安全换算、切换和低功耗行为 保证长期计时与恢复连续性
P1 修订软 RTC source 同步及亚秒处理 自读重设不能作为纠漂,且有回退风险
P1 最小 timekeeper:解耦 RTC 设备与运行期系统时间维护 减少硬件访问并统一状态所有权
P2 复用/改造目标平台现有 EVENT 后端,评估接入自由运行 source,初期保留 OS tick 路径 平台按需能力,通用抽象与库驱动 EVENT 已有基础,连续 source 与 CCR 直接编程待目标板验证,不同时重构调度
P2 完善对时采样、step/slew、校频及 RTC 回写策略 在基础语义和一致性可靠之后提高精度
后续 按需统一调度与 hrtimer 的事件仲裁,实现 tickless 共享事件资源前需解决 deadline 合并和调度时间推进

5.3 两阶段事件架构

第一阶段:独立事件通道,先保证正确性。 例如保留既有周期 tick 中断(如 SysTick)产生 OS tick,另用一个独占的自由运行定时器提供连续 source 和比较 event,驱动 hrtimer。此时不存在 hrtimer → OS tick 的必经关系,系统日历时间统一由 timekeeper 外推。

flowchart LR
    subgraph TIM["独占自由运行定时器(如 32 位 TIM)"]
        CNT["待增/待验 · 计数读取 / 回绕扩展后端"]
        CCR["需改/待验 · 复用/改造现有 EVENT 的比较编程 / ISR 后端"]
    end
    CNT --> Source["已有 · clock source 抽象"] --> TK["待增 · 统一 timekeeper"]
    TK -->|当前时间 / deadline 换算| HR["需改 · hrtimer 时间域联动"]
    HR -->|设置下一事件| Event["已有 · clock event 抽象"]
    Event -->|编程| CCR
    CCR -->|比较中断 / 到期处理| HR
    SysTick["已有 · 周期 tick 中断(如 SysTick)"] --> Tick["已有 · OS tick"]
    Tick --> Sched["已有 · 调度 / 时间片"]
    Tick --> Hard["已有 · rt_timer 硬定时器 / 中断回调"]
    Tick -.->|计时依赖| SoftThread["已有 · 软件定时器线程"]
    SoftThread --> Soft["已有 · rt_timer 软定时器 / 线程回调"]
    classDef existing fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
    classDef modify fill:#fff3e0,stroke:#ef6c00,color:#7f3600
    classDef missing fill:#ffebee,stroke:#c62828,color:#8e0000
    classDef verify fill:#f5f5f5,stroke:#616161,color:#212121
    class Source,Event,SysTick,Tick,Sched,Hard,SoftThread,Soft existing
    class HR modify
    class CNT,TK missing
    class CCR verify
Loading

第二阶段:按需统一事件仲裁。 将调度器、tick 定时器和 hrtimer 的下一截止时间转换到可比较的基准,选择最近事件后编程硬件:

统一仲裁不等于必须把 tick 实现成一个普通 hrtimer 回调。调度时间的推进、时间片、到期处理顺序和中断上下文约束需要由内核明确规定,不能仅按“每次中断加一个 tick”处理。深睡期间还需由 PM 选择可用的低功耗事件设备,并在恢复后补偿和重挂。

5.4 现状与目标差距清单

模块或连接 当前基础 缺少或需要修改的部分
统一 timekeeper【待增】 软 RTC 有基线外推,Smart VDSO 有 realtime offset 复用已有能力,统一状态所有权、计数换算、日历偏移和读写发布;不是从零新增所有计时算法
统一设时入口【待增】 settimeofday/clock_settime 可通知 VDSO,其他入口不一致 stime、set_timestamp、实际 NTP 等入口统一接入;保证 RTC、内核与 VDSO 一致,定义时间可信度状态
libc 时钟语义【需改】 多种 clockid 已有接口,但部分共用同一 boottime,CPU clocks 为 TODO 明确支持范围、RTC 精度回退与错误行为;区分 MONOTONIC/BOOTTIME,不能将 uptime 冒充 CPU 时间
RTC 授时与回写【需改】 RTC 框架和硬件驱动已有,libc 当前主要直接访问 rtc 接入统一启动授时和受控回写策略;运行期 REALTIME 与具体 RTC 设备解耦
软 RTC【需改】 已有基线法和周期任务 修复指定 source 未实际使用及亚秒丢失问题;迁移后不能与 timekeeper 双重维护状态
source/event 抽象【已有】 clock_time_core 与相关设备接口 保留复用;具体 source 的回绕、变频、切换和睡眠行为需逐项验证
目标平台 TIM 后端【需改/待验】 部分平台库驱动已通过 rt_clock_timer_register/rt_clock_timer_isr 提供 EVENT;连续自由运行 SOURCE 尚缺 复用/改造现有 EVENT 后端,评估新增自由运行 SOURCE(64 位一致读取、回绕扩展、比较竞态处理与资源独占);需目标板配置验证
hrtimer【需改】 队列、到期回调、事件编程和 tick 回退已有 补目标时间域转换与改时/校频后的事件重编程;处理 32 位半圈范围,不必重写基础队列
OS tick【已有】 SysTick/架构定时器推进调度 tick 第一阶段保留;第二阶段才改造截止时间导出和统一事件分发
rt_timer 软/硬定时器【已有】 硬定时器在 tick 中断路径回调,软定时器由专用线程处理 第一阶段保持 API、tick 单位和上下文语义;统一仲裁时接入硬定时器 deadline 与软定时器线程唤醒需求,避免重复登记线程超时
PM【需改/待验】 已有低功耗计时器与 tick 补偿 扩展到独立 source、hrtimer 和低功耗事件协调;按 BSP 验证,不能称为完全无补偿
NTP/PTP 接入与调时策略【需改/待增】 有包或可选组件,版本和实际调用链需确认 统一接入设时服务;按需求补采样、slew/校频与状态管理,不认定所有协议能力已集成
统一事件仲裁【待增,后续可选】 各子系统各自具有部分 deadline/事件机制 合并调度、tick 定时器和 hrtimer 的最近事件,定义处理顺序与调度时间推进;不是当前已有功能

本表是目标差距,不代表每个部署都需要实现所有可选能力。优先级见 5.2,代码依据见第 3 节,验证见第 7 节。

5.5 系统启动时 REALTIME 的来源

当前行为

当前通用 libc 主要在读取时访问 rtc 设备,不是统一的“启动读一次 RTC,装入独立 timekeeper”的 hctosys 模型。

启动配置 初始日历时间来源与限制
硬件 RTC 已注册且时间有效 读取硬件 RTC 当前时间;是否跨掉电保持取决于备用电源与驱动初始化行为
启用软 RTC 默认日期基线加运行时间增量;未授时不代表日期可信
开启 RTC 支持但无 rtc 设备 通用 libc 日历时间读取失败
未开启 RTC 支持 通用 time()/gettimeofday() 失败;所查 POSIX clock 实现中 REALTIME 落入 boottime,不能视为有效日期

软 RTC 的 SOFT_RTC_TIME_DEFAULT 未覆盖时为 RTC_TIME_INIT(2018, 1, 1, 0, 0, 0),在初始化中以 timegm() 建立基线,见 components/drivers/rtc/dev_soft_rtc.c:22–35、294–348。这只是初始占位日期,不是自动获取的网络时间。

硬件 RTC 设备存在也不等于时间有效。需要检查电池失效、振荡器停止、硬件有效标志以及驱动是否提供错误反馈;具体驱动可能具有各自的默认日期或初始化策略,不能一概假定保留时间。另外,当前 clock_gettime(REALTIME) 需要相应 RTC TIMESPEC 命令支持,不能仅依据 time() 可用就认定它可用。

Smart VDSO 启动时 realtime offset 尚未就绪:vdso_kernel.c:59–60、164–218 通过有效标志控制快路径,未就绪时用户态回退 syscall。当前 settimeofday()/clock_settime() 可建立 offset,但启动时不会仅因 RTC 已注册就自动完成该步骤。因此,RTC 已正确走时并不代表 VDSO REALTIME 快路径已经有效;周期发布 monotonic 数据也不等于完成日历授时。

目标启动流程【待增:统一启动授时与发布】

flowchart TD
    Start["初始化 clock source 与统一 timekeeper"] --> Check{"选定硬件 RTC 可读<br/>且时间有效?"}
    Check -->|是| RTC["采样 RTC 与当前 counter<br/>建立 REALTIME 基线 / 记录 RTC 来源"]
    Check -->|否| Saved{"有可用的持久时间记录?"}
    Saved -->|有| Restore["恢复最后已知时间下界或估计值<br/>标记未同步"]
    Saved -->|无| Default["采用明确的初始基准<br/>标记未授时"]
    RTC --> Publish["统一发布内核 / libc / VDSO 时间状态"]
    Restore --> Publish
    Default --> Publish
    Publish --> Wait["timekeeper 持续计时"]
    Wait --> Sync["可信 NTP / PTP / 人工授时可用后<br/>经统一入口校准并更新状态"]
    Sync --> Publish
    classDef missing fill:#ffebee,stroke:#c62828,color:#8e0000
    class Start,Check,RTC,Saved,Restore,Default,Publish,Wait,Sync missing
Loading

本图红色表示统一流程待建立,并非 RTC 驱动、VDSO 或协议组件全部缺失。应在所选 RTC 可用且时间发布基础设施就绪后完成一次协调初始化;异步或较晚注册的 RTC 需要明确后续授时策略,不应由每个 RTC 驱动无条件覆盖系统时间。

启动授时还应满足以下约束:

  1. RTC 来源 ≠ 可信网络同步:是否足够可信由产品策略决定。
  2. 持久记录 ≠ 准确当前时间:不知掉电时长,只能作最后已知时间/下界;持久化可选,需考虑写入寿命。
  3. 无有效源仍可持续计时,但必须可识别未授时:明确 API 初始值/失败语义;统一初始化所有读取路径;后续校准不重置硬件 counter 或调度 tick。

5.6 授时源与系统时间的同步方向仲裁

有外部授时时周期将系统时间回写 RTC、无外部授时时 RTC 锚定系统时间——这不是两套机制,也不是 RTC 的特例,而是一个通用仲裁框架的两种结果:同步永远是“高可信源 → 低可信方”的单向流动,方向由各源可信等级决定,由 timekeeper 统一仲裁。RTC 只是授时源的一种实例。

5.6.1 授时源集合与可信等级

系统可接入的授时源不限于 RTC,每个源用同一组属性描述,由产品策略赋予可信等级:

授时源实例 持久性 接入实现的典型粒度 典型可用性
硬件 RTC(片上/外置) 跨断电持续走时(依赖备用供电与有效标志) 秒级(部分有亚秒寄存器) 本地常驻
静态持久记录(flash/文件时间戳) 仅存最后已知点,不持续走时 取决于实现 启动时一次
NTP/SNTP 不持久 协议时间戳含秒的小数部分;实际粒度取决于接入实现(本项目所查 netutils 客户端只取整数秒) 依赖网络
PTP / GPS(1PPS 等) 不持久 捕获能力亚微秒级~消息粒度,端到端精度取决于硬件与链路条件 依赖硬件与链路
人工 / 主机串口授时 不持久 不限于整数秒,取决于输入与接线方式 事件性

粒度列描述的是具体接入实现的能力,不能由协议名直接推断端到端精度。

方向规则:当前最高可信源授时系统;系统可信级高于某持久源时,才向该持久源受控回写。同一时刻只有一个权威源,不存在多源同时写系统时间。

可信等级(示例):未授时 < 静态持久记录(下界)< RTC(持续走时)< 人工/NTP < PTP/GPS

方向规则:
  系统可信级 < 源 S 可信级  →  S ──► 系统(锚定/授时,禁止向 S 回写)
  系统可信级 > 持久源 P 可信级 → 系统 ──► P(受控低频回写)

等级仅针对已通过有效性、来源及质量校验的样本;协议类型本身不构成可信度保证——未认证的公网 NTP 不一定优于维护良好的 RTC,失锁的 GPS 不一定优于有效 NTP。可信等级表是产品策略,不是框架硬编码(见 5.6.4)。

注意区分两类“持久源”:持续走时源(RTC,断电期间仍走时)可参与周期锚定与校频;静态持久记录(flash/文件时间戳)只保存最后已知点,仅用于启动恢复下界,不得用于周期锚定或校频——用同一静态记录重复锚定会使系统时间回退,用其差值校频没有物理意义。

5.6.2 状态机

stateDiagram-v2
    [*] --> 持久源锚定: 启动时有有效持续走时源(5.5,条件式)
    [*] --> 未授时: 无持久源或读数无效
    未授时 --> 持久源锚定: 持续走时源读数有效
    未授时 --> 外部授时: 外部源校验通过(无持久源时直达)
    持久源锚定 --> 外部授时: 更高可信源校验通过(方向反转:源→系统→持久源)
    持久源锚定 --> 未授时: 锚定源确认失效(振荡器停止/掉电失效;瞬时读错误经产品策略的确认阈值判定,不直接降级)
    外部授时 --> 失锁保持: 授时源失效(按已校或名义频率走时)
    失锁保持 --> 外部授时: 授时恢复
    失锁保持 --> 持久源锚定: 长期失效且持久源更可信(滞回后回退)
    外部授时 --> 外部授时: 更高可信或同级替代源校验通过(平滑交接)
Loading

下表为完整能力示例(各行为可按 5.6.4 的裁剪自由度简化):

状态 权威源 持续走时源 → 系统 系统 → 持久源回写
持久源锚定(典型:仅硬 RTC) 持续走时源 周期锚定、长窗校频(均按 5.6.4 裁剪自由度取舍)或仅启动对齐(见 5.6.3) 禁止——系统没有比持久源更准的依据
外部授时 外部源 停止,持久源不再仲裁系统 启用时低频周期回写(类比 Linux 11 分钟模式,仅在已同步状态执行)
失锁保持(holdover) 系统(已校或名义频率) 停止 按产品策略:可继续或暂停

5.6.3 慢速/低分辨率源的锚定方法

持久源(RTC 通常秒级)分辨率低于系统 counter(亚秒级)时,正确分工不是互比两个完整时间戳,而是各管一段——该方法适用于任何比系统 counter 慢的锚定源:

系统时间 = 源读数(锚点,精确到其分辨率)+ counter 外推的亚分辨率偏移
T_sys(t) = T_src_k + (c(t) − c_k) / freq
  1. 边界锚定:源读数在其分辨率内的亚部分本来未知,理想锚点打在读数翻转处。但周期事件不天然等于时间边界:RTC wakeup 可从使能时刻起计、相位不保证对齐日历秒;GPS 1PPS 需有效锁定且需时间标签指明脉冲对应的整秒,单独脉冲不能确定日期与秒号。只有已验证与时间标签边界对应的事件才可直接打点(误差含中断/唤醒/调度/读取延迟);否则采用有界采样窗口(如轮询翻转),并显式报告打点不确定度。
  2. 比较只在源边界进行:禁止直接 系统时间 − 源读数 判漂移——源的量化噪声(秒级源 ±0.5~1 秒)会被误当成系统漂移,引入虚假 step。诊断时将系统读数截断到源分辨率再比较,仅用于越界粗检。
  3. 量化误差不积累,频率误差积累:长窗校频把量化误差摊薄——端点量化误差固定,相对频率测量不确定度 ≈ 端点量化与打点误差之和/测量窗(秒级源、天级窗约 ±12 ppm 量级)。这是测量分辨能力,不是系统相对 UTC 的误差保证,也不消除参考源自身频偏。校准值可低频持久化,重启后加载前需确认 source 频率配置与硬件未变更(温度漂移需重新收敛)。
  4. 锚点更新的相位修正:残余大小不预设——打点条件良好时可小至 µs~ms 级,非对齐事件或低频轮询可能达明显秒内比例。按测得残余、误差界与产品阈值决定:小残余并入换算系数做有界、渐进的相位修正(重建连续锚点,维持非负走时速率,不重新解释历史 counter,不破坏 deadline 契约);超出阈值走 step/告警路径。
  5. 精度误差预算:系统日历精度上限 = 权威源自身精度 + 量化与打点/传输延迟 + 外推期频率误差,无法突破源本身;源的亚分辨率能力(如 RTC 的 SSR 类寄存器)是加分项,非通用假设。

5.6.4 仲裁规则

任何配置都必须满足的不可裁约束:同步是高可信源→低可信方的单向流动;方向判定只有唯一仲裁点;启动优先由有效持续走时源→系统重建基线,仅有静态持久记录时恢复最后已知时间下界并保留未授时标记,无源则明确未授时、外部源可直接接管。

  1. 唯一仲裁点:方向判定只在统一设时入口/timekeeper;驱动、协议客户端、shell 不得自行决定写持久源或锚定系统。
  2. 可信等级由产品定义:排序与升降级条件是策略;切换滞回——源短暂抖动不触发方向反复切换,失锁先进入 holdover 观察期。
  3. 回写前置条件:系统已获可信授时才回写(类比 Linux ntp_synced());回写前比较差异,阈值内可跳过;flash 类记录考虑写入寿命。
  4. 回写粒度匹配持久源语义:任意时刻截断写秒级 RTC 引入近 1 秒相位偏差,须借秒边界或按设备生效规则处理。
  5. 掉电闭环:有持续走时源时启动优先由其→系统重建基线;无源进入未授时,外部源可直接接管。

能力可裁部分:holdover 可裁,滞回可简化为固定阈值,周期锚定与校频可独立于状态机裁剪,回写可整项裁掉(仅损失跨断电的最近一次授时结果),多源分级可退化为持久源/授时源两档;能力取舍与 6.2 的系统整体配置档相互独立、可组合。

本节是工作项 D(授时状态与边界)与第 6 节第 3 步的架构依据;方向仲裁本身不要求新增硬件,但周期锚定需使用已验证与时间标签边界对应的事件,或采用有界采样窗口,并计入打点不确定度。

6. MCU 适配与分阶段实施

本章是普通 MCU 上的分步实施路径与裁剪边界。本章是实施建议,不代表已实现;每步验收均受第 3 节的证据边界约束,量化目标由产品定义并以实测确认,本文不提供未验证的精度数值。

6.1 目标定位:正确性契约与分档能力,而非 Linux 移植

  • 目标不是移植 Linux timekeeping。 落地两条主线:①正确性契约——所有读取路径一致、设时入口统一、不支持的语义明确拒绝;②分档能力——最小核心满足小系统,高精度/对时/校频按需叠加。
  • 普通 MCU 走完第 1–3 步即阶段性终点。 第 4、5 步是平台增强与高级能力,不做不破坏前三步契约。
  • 无硬 RTC 系统:运行期日历 = 基线 + 单调计数经过;断电期间无法准确走时;持久记录只能作下界(5.5)。这是固有能力边界,应如实暴露授时状态。

6.2 最小可裁剪核心与可选能力

按“最小核心 + 可选叠加”组织能力,每个配置档只要求其声明范围内的行为正确:

层级 内容 裁剪属性
最小核心 调度 tick;至少一条语义如实的日历时间读取路径(可用,或明确不可用);统一设时入口(至少覆盖人工设时) 任何目标配置都应满足
基础可选 软/硬 RTC 接入统一基线;授时状态(来源、有效性)可查询;RTC 驱动能力矩阵与兼容回退 无 RTC 设备不等于裁掉日历服务:仍可经人工/网络授时启用软件日历;完全不提供日历服务时才可裁,但读取需如实返回不可用
进阶可选 VDSO 快路径一致性;MONOTONIC/BOOTTIME 的 suspend 语义区分;NTP/SNTP 授时;hrtimer 独立事件后端 按产品需要启用,启用才参与验收
高级可选 slew/校频与 RAW 区分;RTC 受控回写;统一事件仲裁与 tickless 有明确指标要求时才投入

MCU 典型配置档(描述行为契约,不含未验证的精度指标):

配置档 组件组合 可达效果 明确不具备
裸最小 最小核心;无 RTC 运行期时间可读、可人工设置;未授时状态如实暴露 跨断电走时、POSIX 完整矩阵、高精度
基础日历 + 软/硬 RTC 接入统一基线与状态查询 time/gettimeofday/clock_gettime(REALTIME) 一致;授时后运行期日历可信 suspend 语义区分、网络对时、高精度
标准低功耗 + 启动授时/持久下界 + PM 边界闭环 第 1–3 步阶段性终点;睡眠前后各时钟符合声明语义 高精度事件、校频、tickless
高精度 + 平台 source/event 后端 亚 tick 粒度延时与定时,事件实际生效可查询 校频与统一仲裁(属高级档)
高级 + 对时增强/slew 校频/统一事件仲裁 长期精度与功耗的精细优化 —(全部按需实现)

6.3 建议分五步实施

每步给出范围、适用场景、完成验收与可裁项。验收均为行为验收;量化指标由产品定义并以实测确认。

第 1 步:现有接口一致与兼容(对应 3.8.1–3.8.3,建议工作项 A/C)

  • 范围:
    • stime、set_timestamp、实际 NTP 等入口统一接入同一更新协议并同步 VDSO(无 VDSO 时保持单一协议)。
    • 建立 RTC 驱动秒/timeval/timespec/resolution 能力矩阵,统一兼容回退或明确不支持。
    • 明确各 clockid 支持矩阵、初始状态与错误行为;未实现的 CPU clock 等明确拒绝。
  • 适用场景:所有启用 RTC 或 POSIX clock 的配置;不依赖硬件改动,可最先开展。
  • 完成验收:
    • 逐一调用各设时入口后,各读取路径在采样延迟与设备分辨率允许范围内一致。
    • 能力矩阵可查询,分辨率报告与实际能力一致;日历 step 不影响相对超时与单调时序。
  • 可裁项:无 VDSO 可裁 VDSO 通知但保留单一协议;无 POSIX clock 可只做入口统一与错误行为文档化。

第 2 步:最小软件日历(最小 timekeeper,对应 3.8.4、5.1,建议工作项 B)

  • 范围:
    • 以软 RTC"日历基线 + 运行时间增量"结构为基础提取最小 timekeeper:日历基线 + counter 换算 + 统一读写发布。
    • REALTIME 运行期统一经 timekeeper,不再逐次访问 RTC 设备;无硬 RTC 系统由此承担运行期走时(边界见 6.1)。
    • 修复软 RTC 自读自写与丢弃亚秒;所选基础 source(含默认 tick source)的回绕连续性与溢出安全换算在本步闭环(见 3.8.5),不随高精度步骤裁剪。
  • 适用场景:无硬 RTC 但需要运行期日历的系统;有硬 RTC 且希望解耦设备访问、统一状态所有权的系统。
  • 完成验收:初始化采样一致性与运行期误差分开验收。
    • 有硬 RTC:启动采样建基线后运行期读取不触发设备访问,采样时刻与直接读设备在采样误差与分辨率允许范围内一致;运行期差异按实际频偏与产品误差预算评估(两源晶振不同会自然漂移)。
    • 无硬 RTC:授时后走时连续、未授时状态可查询;跨 source 回绕与换算溢出临界点读数连续;日历 step 不污染单调计数;软 RTC 保留时不与 timekeeper 双重维护状态。
  • 可裁项:极小系统可暂不启用独立 timekeeper(仍受第 1 步契约约束);授时状态可先只分"未授时/已授时"两态。

第 3 步:授时与低功耗边界(对应 3.8.8–3.8.10 基础部分、5.5、5.6,建议工作项 D)——普通 MCU 阶段性终点

  • 范围:
    • 按 5.5 实现启动授时(RTC 有效则授时、持久记录作最后已知时间下界、无源标记未授时)并统一发布到各读取路径。
    • 按 5.6 实现同步方向仲裁(三条红线不可裁,锚定/回写等能力按 5.6.4 的裁剪自由度取舍);NTP/SNTP/人工授时统一入口,不旁路直写 RTC。
    • 逐电源模式确认独立 source 是否停走、event 能否唤醒、补偿由谁执行,tick 补偿与 sleep offset 不重复计。
  • 适用场景:有低功耗、网络授时需求,或需要明确"时间不可信"语义的产品。
  • 完成验收:
    • 启动、晚注册 RTC、首次网络授时均经同一发布流程,读取结果与授时状态一致。
    • 各电源模式同时测量 tick、MONOTONIC、BOOTTIME 与 REALTIME,符合声明 suspend 语义,不漏计不重计;对时异常有可观测状态。
  • 可裁项:无网络产品可裁 NTP,仅保留人工与 RTC 授时;不使用深睡可声明不支持的电源模式;授时状态可先只在内核内一致。

完成第 1–3 步即普通 MCU 的阶段性终点:正确性契约成立,运行期日历可信(授时后),授时与低功耗边界明确。

第 4 步:高精度按需(平台相关,对应 3.8.5 新增 source 部分、3.8.6–3.8.7,建议工作项 E)

  • 范围:
    • 为选定平台接入自由运行 source 与独立 event 后端;新增平台 source 的回绕扩展与单次 deadline 范围处理(默认/既有 source 已在第 2 步闭环)。
    • 实际生效的 source/event/owner/回退状态可查询;回调上下文、可调用 API 与重入契约明确(已过期 deadline 可能在 start 调用线程上下文同步执行回调,见 3.8.7)。
  • 适用场景:需要亚 tick 精度延时与定时的产品;按平台逐个实现,不要求全平台覆盖。
  • 完成验收:以真实事件链和延迟测量验收,而非只看配置宏或 API 名称;跨回绕读数连续;超范围请求可分段或可诊断拒绝;回调约束有测试覆盖并测最坏延迟。
  • 可裁项:tick 回退路径保留为兼容机制;无高精度需求可整步跳过,不影响前三步契约。

第 5 步:高级能力按需(对应 5.2 P2 与后续项,建议工作项 F)

  • 范围:slew 与校频(区分 MONOTONIC 可调速与 RAW 不调速);RTC 受控回写策略(由授时状态与产品策略决定);统一事件仲裁与 tickless(5.3 第二阶段)。
  • 适用场景:对长期精度、功耗有明确指标,且愿意投入独立参考源测量验证的产品。
  • 完成验收:
    • 以独立可信时间源测量长期误差并达到产品自定目标;校频不修改 RAW。
    • 相对超时不受日历 step 污染;校频按声明时间域换算并按需重编程事件,不倒退、不重复触发、不意外取消;统一仲裁后既有回调契约不被破坏。
  • 可裁项:全部可裁;无此需求停在第 3 或第 4 步即可。

同一底层改动可能同时服务多步(如统一设时入口贯穿第 1、3 步),实现时可合并设计、分开验收;步骤划分不改变第 3 节各问题的证据与边界。

7. 后续验证清单

以下清单与第 6 节步骤对应:第 1 条是第 2/4 步前置确认;第 2–6 条对应第 1/2 步;第 7–8 条对应第 2/3 步;第 9 条对应第 5 步。步骤被裁剪时对应清单项随之裁剪。

  • 确认目标 BSP、.config、clock source、计数器位宽及实际频率。
  • 覆盖有无 RTC、有无 CLOCK_TIME、旧 RTC 与 DM RTC、Smart/VDSO 等配置。
  • 交叉验证 time、gettimeofday、clock_gettime 和 VDSO 的读数与错误行为。
  • 分别调用 settimeofday、clock_settime、stime、set_timestamp 和实际 NTP 入口,检查各路径一致性。
  • 测试正向/反向 step 不影响相对超时和单调时序。
  • 测试 tick 回绕、counter 回绕、源切换前后连续性。
  • 测试 tickless idle 与不同 suspend 模式,分别覆盖计数源停走和继续运行的情况。
  • 固定 netutils/lwIP 版本,核对实际构建、设时钩子和启动调用链。
  • 以独立可信时间源测量长期频率误差,不用自读重设证明“纠漂有效”。

8. 外部参考

外部在线源码与文档的核查日期为 2026-10-24;链接指向 main/master/latest 的内容可能随后变化,引用本文结论前建议复核。

Activity

  1. github-actions commented on Oct 24, 2026

    @github-actions

    如需认领并处理此 Issue,请评论 /claim。

    To claim and work on this issue, comment /claim.

  2. changed the title [-]时间子系统调研:设时一致性、clock 语义与计时连续性问题及统一时间维护建议[/-] [+][Feature] 时间子系统调研:设时一致性、clock 语义与计时连续性问题及统一时间维护建议[/+] on Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions