内核定时器与高精度定时器(hrtimer)的实现原理 内核定时器与高精度定时器(hrtimer)的实现原理一、Linux定时器体系的演进Linux内核有四种定时器机制。jiffies定时器最古老精度为tick级别1ms-10ms。timer_list基于jiffies用于大多数驱动。hrtimer基于ktime精度达纳秒级。POSIX timer面向用户空间。每次升级都是为了更高的精度和更低的开销。传统timer_list的问题在于精度受限。tick是周期性时钟中断。配置CONFIG_HZ250时tick间隔为4ms。这意味着1ms的定时需求实际延迟为2-4ms。这对实时应用是不可接受的。hrtimer使用硬件时钟事件设备绕过tick限制。精度取决于硬件能力通常可达纳秒级。graph TD subgraph 传统定时器 A[tick中断] -- B[jiffies递增] B -- C[遍历timer_list] C -- D[执行到期定时器] end subgraph 高精度定时器 E[红黑树到期时间] -- F[计算最近到期值] F -- G[编程clockevent设备] G -- H[硬件中断触发] H -- I[执行hrtimer回调] end D -- J[精度: ms级] I -- K[精度: ns级]二、定时器子系统核心数据结构2.1 timer_list与timer_base// include/linux/timer.h struct timer_list { struct hlist_node entry; unsigned long expires; /* 到期jiffies值 */ void (*function)(struct timer_list *); u32 flags; }; // kernel/time/timer.c struct timer_base { raw_spinlock_t lock; struct timer_list *running_timer; unsigned long clk; /* 当前jiffies */ unsigned long next_expiry; unsigned int cpu; bool is_idle; DECLARE_BITMAP(pending_map, WHEEL_SIZE); struct hlist_head vectors[WHEEL_SIZE]; } ____cacheline_aligned;timer_base使用时间轮Timer Wheel数据结构。将定时器按到期时间分散到不同槽位。查找复杂度O(1)。时间轮分为9个级别。第一级256个槽每个槽1个jiffy。第九级256个槽每个槽2^24个jiffies。这是经典的哈希分层时间轮。2.2 时间轮的级联展开/* 时间轮级联迁移的核心逻辑 */ static int __collect_expired_timers(struct timer_base *base, struct hlist_head *heads) { unsigned long clk base-clk; struct hlist_head *vec; int i, levels 0; unsigned int idx; /* 遍历所有到期的槽位 */ for (i 0; i LVL_DEPTH; i) { idx (clk LVL_MASK) i * LVL_SIZE; if (__test_and_clear_bit(idx, base-pending_map)) { vec base-vectors idx; hlist_move_list(vec, heads); levels; } /* 检查是否需要级联 */ if (clk LVL_CLK_MASK) break; /* 向下一个级别级联 */ clk LVL_CLK_SHIFT; } return levels; }三、hrtimer的设计与红黑树实现3.1 hrtimer数据结构hrtimer的核心是用红黑树替代时间轮。红黑树按到期时间排序。最小到期时间的节点在红黑树的最左端。查找下一个到期事件只需取最左节点。// include/linux/hrtimer.h struct hrtimer { struct timerqueue_node node; ktime_t _softexpires; enum hrtimer_restart (*function)(struct hrtimer *); struct hrtimer_clock_base *base; u8 state; u8 is_rel; u8 is_soft; u8 is_hard; }; // kernel/time/hrtimer.c struct hrtimer_cpu_base { raw_spinlock_t lock; unsigned int cpu; unsigned int active_bases; unsigned int clock_was_set_seq; unsigned int hres_active : 1; unsigned int in_hrtirq : 1; ktime_t expires_next; struct hrtimer *next_timer; unsigned int nr_events; unsigned int nr_retries; struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; }; /* 插入定时器到红黑树 */ static void enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, enum hrtimer_mode mode) { /* 将定时器节点插入timerqueue红黑树 */ timerqueue_add(base-active, timer-node); /* 更新最左节点的到期时间 */ if (timer-node base-active.next) { base-cpu_base-active_bases | (1 base-index); hrtimer_update_next_event(base-cpu_base); } }3.2 高精度模式的激活系统在满足条件时可切换到高精度模式。需要硬件clockevent设备支持oneshot模式。中断延迟足够低。hrtimer子系统接管时钟中断。/* 切换到高精度定时器模式 */ static int hrtimer_switch_to_hres(void) { struct hrtimer_cpu_base *base this_cpu_ptr(hrtimer_bases); if (base-hres_active) return 1; /* 接管tick设备 */ tick_setup_sched_timer(); base-hres_active 1; /* 重新编程clockevent设备为oneshot模式 */ hrtimer_force_reprogram(base, 0); return 1; }3.3 到期处理与再编程sequenceDiagram participant HW as 硬件定时器 participant ISR as hrtimer_interrupt participant RB as 红黑树 participant CB as 回调函数 HW-ISR: 时钟中断触发 ISR-RB: 取最左到期节点 RB--ISR: timer_node loop 有到期定时器 ISR-RB: 移除节点 ISR-CB: 执行callback CB--ISR: HRTIMER_RESTART/NORESTART alt 需要重启 ISR-RB: 重新插入(新到期时间) end ISR-RB: 取下一个到期节点 end ISR-HW: 编程下一次到期时间/* hrtimer中断处理的核心函数 */ void hrtimer_interrupt(struct clock_event_device *dev) { struct hrtimer_cpu_base *cpu_base this_cpu_ptr(hrtimer_bases); ktime_t expires_next, now; int retries 0; now hrtimer_update_base(cpu_base); cpu_base-nr_events; __hrtimer_peek_ahead_timers(); for (int i 0; i HRTIMER_MAX_CLOCK_BASES; i) { struct hrtimer_clock_base *base; struct timerqueue_node *node; ktime_t basenow; base cpu_base-clock_base i; basenow ktime_add(now, base-offset); /* 遍历所有到期的定时器 */ while ((node timerqueue_getnext(base-active))) { struct hrtimer *timer; timer container_of(node, struct hrtimer, node); /* 检查是否真正到期 */ if (basenow hrtimer_get_expires_tv64(timer)) break; /* 从红黑树中移除 */ __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0); /* 执行回调 */ if (timer-function(timer) ! HRTIMER_RESTART) continue; /* 需要重启的重新入队 */ enqueue_hrtimer(timer, base, HRTIMER_MODE_PINNED); } } /* 重新编程下一次中断 */ expires_next __hrtimer_get_next_event(cpu_base); if (expires_next ! KTIME_MAX) { tick_program_event(expires_next, 1); } }四、使用示例与最佳实践4.1 驱动中使用timer_list#include linux/timer.h #include linux/module.h struct my_device { struct timer_list poll_timer; unsigned long poll_interval_ms; /* ...其他字段... */ }; static void poll_timer_callback(struct timer_list *t) { struct my_device *dev from_timer(dev, t, poll_timer); /* 执行轮询逻辑 */ dev_check_status(dev); /* 重新设置定时器 */ mod_timer(dev-poll_timer, jiffies msecs_to_jiffies(dev-poll_interval_ms)); } static int my_drv_probe(struct platform_device *pdev) { struct my_device *dev; dev devm_kzalloc(pdev-dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev-poll_interval_ms 500; /* 初始化并启动定时器 */ timer_setup(dev-poll_timer, poll_timer_callback, 0); mod_timer(dev-poll_timer, jiffies msecs_to_jiffies(dev-poll_interval_ms)); return 0; } static int my_drv_remove(struct platform_device *pdev) { struct my_device *dev platform_get_drvdata(pdev); /* 同步删除定时器 */ del_timer_sync(dev-poll_timer); return 0; }4.2 高精度定时器的使用#include linux/hrtimer.h struct high_precision_poller { struct hrtimer hr_timer; ktime_t period; }; static enum hrtimer_restart hr_poll_callback(struct hrtimer *timer) { struct high_precision_poller *poller container_of(timer, struct high_precision_poller, hr_timer); /* 高精度轮询逻辑 */ hrtimer_forward_now(timer, poller-period); return HRTIMER_RESTART; } void setup_high_precision_timer(struct high_precision_poller *poller, u64 interval_ns) { poller-period ns_to_ktime(interval_ns); hrtimer_init(poller-hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); poller-hr_timer.function hr_poll_callback; hrtimer_start(poller-hr_timer, poller-period, HRTIMER_MODE_REL); } void cleanup_timer(struct high_precision_poller *poller) { hrtimer_cancel(poller-hr_timer); }五、性能陷阱与调优5.1 常见问题问题原因解决办法定时器精度不足使用timer_list改用hrtimer回调执行时间长在软中断上下文做重活使用workqueue延迟大量定时器导致CPU load高遍历开销大使用时间轮合并hrtimer精度漂移系统负载波动使用CLOCK_MONOTONIC_RAW# 查看定时器统计 cat /proc/timer_list # 查看hrtimer详细信息 cat /proc/timer_list | grep -A10 hrtimer # 内核tracepoint追踪定时器 echo 1 /sys/kernel/debug/tracing/events/timer/timer_start/enable echo 1 /sys/kernel/debug/tracing/events/timer/hrtimer_start/enable cat /sys/kernel/debug/tracing/trace_pipe总结深入Linux内核定时器体系的实现原理。对比了timer_list基于jiffies的时间轮机制与hrtimer基于ktime的红黑树机制。timer_list使用9级哈希时间轮实现O(1)插入精度受限于tick间隔。hrtimer用红黑树替代时间轮通过clockevent设备的oneshot模式实现纳秒级精度。给出hrtimer_interrupt完整中断处理流程包括到期遍历、回调执行、重启入队和下一次中断编程。提供驱动开发中的timer_list和hrtimer使用模板。归纳了精度不足、回调阻塞、CPU负载和精度漂移四大陷阱及对策。

相关新闻

最新新闻

影刀RPA 报表自动调度:定时查询数据库并生成业务报表

影刀RPA 报表自动调度:定时查询数据库并生成业务报表

影刀RPA 报表自动调度:定时查询数据库并生成业务报表 作者:林焱 什么情况用什么 大多数公司都有几个"祖传报表":每天早上销售总监要看前一天的销售额,每周一运营总监要看上周的用户增长,每月1号财务要看上…

2026/7/16 0:30:11
影刀RPA 批量操作的断点记录与续跑方案

影刀RPA 批量操作的断点记录与续跑方案

影刀RPA 批量操作的断点记录与续跑方案 作者:林焱 什么情况用这个 处理5000条数据到第3891条时流程中断了。你重启流程——从头开始。前3891条白跑了,还要花同样的时间重新处理。更糟的是,前面已经提交到系统的数据没法"撤回"&…

2026/7/16 0:30:11
Windows系统文件DaOtpCredentialProvider.dll丢失找不到问题解决

Windows系统文件DaOtpCredentialProvider.dll丢失找不到问题解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…

2026/7/16 0:30:11
影刀RPA 批量处理的进度追踪:让长任务可视化

影刀RPA 批量处理的进度追踪:让长任务可视化

影刀RPA 批量处理的进度追踪:让长任务可视化 作者:林焱 什么情况用这个 你在跑一个处理5000条数据的流程,半个小时过去了,窗口没有任何反应——不知道处理到第几条了、还要多久、有没有卡死。你犹豫要不要手动关掉重来&#xff0c…

2026/7/16 0:30:11
告别网盘限速烦恼:LinkSwift直链下载助手完整使用指南

告别网盘限速烦恼:LinkSwift直链下载助手完整使用指南

告别网盘限速烦恼:LinkSwift直链下载助手完整使用指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

2026/7/16 0:30:11
ReAct框架:让你的AI智能体从“问答机器人”升级为“全能帮手”(收藏版)

ReAct框架:让你的AI智能体从“问答机器人”升级为“全能帮手”(收藏版)

ReAct框架通过“思考-行动-观察”的闭环机制,有效弥补了大型语言模型在知识时效性、运算执行能力和外部环境联动方面的短板。它将LLM的逻辑推理能力与外部工具(如网络搜索、计算器、API接口)相结合,使AI智能体能够自主拆解规划任务…

2026/7/16 0:25:11

月新闻