[Feature] 对 hwtimer/ktime/cputime 进行整体重构
Describe problem solved by the proposed feature
目前 hwtimer/ktime/cputime 整体非常乱,应该从整体维度上进行重构,让它有一个更好的架构:
- 简单清晰;
- 针对MCU场景考虑,针对MPU场景考虑;
- 反映到实时场景下的要求;
- 如进行更改,应对所有涉及到的bsp进行检查并进行修改,至少保证构建无错,qemu测试通过;
对于这部分的重构,应该先给出整体设计,涉及到的文件评估,完成重构,ci涉及到的每个bsp构建,qemu测试通过。
Describe your preferred solution
No response
Describe possible alternatives
No response
RT-Thread 时间子系统(ktime / cputime / hwtimer)分析
OS 时间子系统包含的主要部分
- 时间基准(Time Source / Clocksource):提供连续、单调递增的计数值和频率信息,支持时间戳、运行时间统计等。
- 事件源(Clockevent / Oneshot Timer):可编程定时事件,设定相对当前计数的到期点,到期触发中断。
- 时间换算与基准时间:把计数值换算成 ns/us/ms,并维护开机以来的单调时间(boottime)。
- 高精度定时器调度器:在事件源之上管理多路定时器(链表/红黑树),提供睡眠、周期/一次性定时 API。
- 兼容层与设备抽象:面向 BSP/驱动提供统一的注册与能力标识,面向上层提供稳定 API,减少重复移植。
现状情况
-
ktime
- 组成:
boottime.c(弱符号,默认用 tick 计数换算 ns/us/s)、cputimer.c(弱符号,默认用 tick;AArch64/virt64 覆写为硬件计数器)、hrtimer.c(链表管理,spinlock 保护)。 - 关键点:
rt_ktime_hrtimer_settimeout作为硬件回调入口,不实现时退化为软定时器;_cnt_convert做 cputimer 周期到 hrtimer 周期的换算,防止大跨度溢出;_set_next_timeout_locked尝试“消化”已过期并立即重新编程下一个超时。 - 优点:有自旋锁,SMP 可用;接口风格与
rt_timer类似,易迁移。 - 问题:cputimer/boottime 采用 weak 函数,BSP 需重复覆写;hrtimer 仍用链表,未使用更高效数据结构;缺少统一驱动抽象,硬件适配散落在 BSP。
- 组成:
-
cputime
- 组成:
rt_clock_cputime_ops(getres/gettime/settimeout),clock_cpu_*工具 API,cputimer.c实现一个基于clock_cpu_settimeout的定时器链表(带信号量 sleep),cputime_cortexm/riscv提供 ops 示例。 - 关键点:
clock_cpu_settimeout允许硬件 oneshot;rt_cputimer_start/stop使用全局中断屏蔽保护链表;rt_cputime_sleep/ndelay/udelay/mdelay提供高精度延时。 - 优点:接口简单,早期 BSP 已广泛使用;提供延时 API 对标
udelay类需求。 - 问题:与 ktime 的 cputimer/hrtimer 职责重叠;链表保护用关中断,SMP 下抖动大;未与 hwtimer 设备类复用,硬件适配重复。
- 组成:
-
hwtimer
- 组成:设备抽象
rt_hwtimer_ops/info/device,实现文件hwtimer.c,以及典型驱动hwtimer-arm_arch.c。 - 关键点:
timeout_calc根据 sec/usec 和 freq/maxcnt 计算合适的 cycles/reload,支持上下计数模式;rt_device_hwtimer_isr维护 overflow/cycles,并通过rx_indicate通知上层;control 支持设频率/模式/获取 info。 - 优点:完整的 device/ops 封装,已有 DM/OFW 集成案例;支持频率自适应选择(尽量 1MHz)。
- 问题:未作为 ktime/cputime 的统一后端;overflow/cycles 逻辑与高精度定时需求高度重合但未复用。
- 组成:设备抽象
总结:ktime 和 cputime 都在提供“高精度计数 + oneshot/定时”能力,但各自一套接口(weak vs ops),应该是ktime是cputime的后期期望改善版本(但改善不彻底)。hrtimer/cputimer 都是链表调度,未复用 hwtimer。
cputime - 是一份简洁版本的cpu time功能,提供对POSIX time的支持(clock_gettime/clock_settime/clock_getres)。而其中又被塞入了一份 定时器 的实现(以链表的方式) hwtimer - 是一份提供硬件外设定时器的设备操作接口的实现; ktime - 期望是一份容纳包括 cputime / bootime,再加上 hrtimer (高分辨率定时器)的实现。但这份实现加入后,又没把之前的给移除……然后就开始堆山了。
POSIX中的clockid_t,常见的包括:(取决于实现,POSIX vs Linux 扩展):
- CLOCK_REALTIME:可被 settimeofday 等调整的墙钟时间。
- CLOCK_MONOTONIC:单调递增,不受手动改时影响(可能受 NTP 微调)。
- CLOCK_MONOTONIC_RAW(Linux):硬件单调计数原始值,不做 NTP 调整。
- CLOCK_BOOTTIME(Linux):含挂起/休眠时间的单调计数。
- CLOCK_REALTIME_COARSE / CLOCK_MONOTONIC_COARSE(Linux):低精度、低开销版本。
- CLOCK_PROCESS_CPUTIME_ID:当前进程占用的 CPU 时间。
- CLOCK_THREAD_CPUTIME_ID:当前线程占用的 CPU 时间。
- CLOCK_TAI(Linux):国际原子时基准,不受闰秒调整。
- 其他平台可能有:CLOCK_VIRTUAL、CLOCK_PROF(部分 Unix 旧实现),以及实现自定义的专用时钟。 Availability 需查各平台的 <time.h>/man page。
RT-Thread 时间子系统 C-OOP 设计方案
引入统一时间设备抽象
clock_time:作为模块目录(如components/drivers/clock_time),聚合时间基准/事件源能力,显式表意且不与rt_timer冲突。rt_clock_time:作为对象/接口前缀,含义是“时间基准/时钟事件的统一抽象”。
struct rt_clock_time_ops
{
rt_uint64_t (*get_freq)(void); /* 计数频率 Hz */
rt_uint64_t (*get_counter)(void); /* 自由运行计数值 */
rt_err_t (*set_timeout)(rt_uint64_t delta); /* 相对当前计数的 oneshot,0 表示取消 */
};
struct rt_clock_time_device
{
struct rt_device parent;
const struct rt_clock_time_ops *ops;
rt_uint64_t res_scale; /* ns * scale / freq -> cnt, 统一精度缩放 */
rt_uint8_t caps; /* bit0: clocksource 可用; bit1: clockevent 可用 */
};
rt_err_t rt_clock_time_device_register(struct rt_clock_time_device *dev, const char *name, rt_uint8_t caps);
- 提供默认
rt_clock_time_default(由 BSP 绑定:可直接封装 hwtimer 的 oneshot + count_get,或架构计数器),作为系统时基。 res_scale固定用RT_KTIME_RESMUL,兼容当前换算逻辑。
目录与功能覆盖情况(clock_time)
- 目录:
components/drivers/clock_time,集中放置抽象、公共实现与适配器。 - 功能:统一覆盖 cputime(高精度计数与换算)、boottime(开机单调时间)、POSIX
clock_gettime/clock_settime支撑、hrtimer(红黑树优先,极简版可链表降级),并保留定时器对象/设备化接口(可由 hwtimer/DM/OFW 实例化)。 - 命名:对外暴露
rt_clock_time_*前缀的对象/函数,避免与rt_timer冲突且表意清晰。
clock_time 引入后,移除 cputime, hwtimer, ktime,都统一收归到 clock_time 中。如原有API有引用,做兼容处理或代码调整。