news 2026/4/16 16:12:22

[Linux外设驱动详解]Linux 定时器系统深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Linux外设驱动详解]Linux 定时器系统深度解析

Linux 定时器系统深度解析

目录

  1. 概述
  2. 定时器类型总览
  3. HZ 定时器 (传统定时器)
  4. 高精度定时器 (hrtimer)
  5. 两种定时器的关系
  6. 硬件定时器层
  7. 完整调用链分析

概述

Linux 内核有多个定时器子系统,它们协同工作提供不同精度的定时服务。理解这些定时器之间的关系对于深入理解内核时间管理至关重要。

核心问题:HZ 定时器和高速定时器 (hrtimer) 是同一个吗?

简短回答:不是同一个。它们是两个独立的定时器系统,使用不同的硬件定时器作为底层支持。


定时器类型总览

Linux 内核定时器层次结构

┌─────────────────────────────────────────────────────────────────────┐ │ 用户空间定时器 API │ ├─────────────────────────────────────────────────────────────────────┤ │ sleep() / usleep() / nanosleep() │ │ timer_create() / setitimer() / alarm() │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 内核定时器子系统 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────┐ ┌──────────────────────────────────┐ │ │ │ 传统定时器层 │ │ 高精度定时器层 (hrtimer) │ │ │ ├──────────────────────┤ ├──────────────────────────────────┤ │ │ │ • timer_list │ │ • hrtimer │ │ │ │ • 基于 jiffies │ │ • 纳秒精度 │ │ │ │ • 时间轮算法 │ │ • 红黑树 + 时间堆 │ │ │ │ • 分辨率: 1/HZ 秒 │ │ • 分辨率: 纳秒级 │ │ │ └──────────────────────┘ └──────────────────────────────────┘ │ │ ↓ ↓ │ │ ┌──────────────────────┐ ┌──────────────────────────────────┐ │ │ │ Tick 设备层 │ │ Tick 设备层 (共享) │ │ │ ├──────────────────────┤ ├──────────────────────────────────┤ │ │ │ • tick_device │ │ • tick_device │ │ │ │ • tick_periodic() │ │ • tick_sched_timer() │ │ │ │ • tick_sched_timer() │ │ • hrtimer_interrupt() │ │ │ └──────────────────────┘ └──────────────────────────────────┘ │ │ ↓ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 时钟事件设备 (clock_event_device) │ │ │ │ │ │ │ │ • clockevents_config_and_register() │ │ │ │ • set_next_event() │ │ │ │ • event_handler() │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 硬件定时器 (ARM 架构定时器) │ │ │ │ │ │ │ │ • ARMv8 System Counter (24MHz) │ │ │ │ • CNTP_TVAL_EL0 / CNTV_TVAL_EL0 │ │ │ │ • GIC PPI 中断 │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘

定时器分类对比表

特性传统定时器 (timer_list)高精度定时器 (hrtimer)
数据结构struct timer_liststruct hrtimer
时间基准jiffiesktime (纳秒)
分辨率1/HZ 秒 (默认 4ms)纳秒级
调度算法时间轮 (Timer Wheel)红黑树 + 时间堆
典型用途设备驱动、超时检查usleep、高精度调度
性能低开销,低精度稍高开销,高精度
中断频率固定 HZ动态,按需触发

HZ 定时器 (传统定时器)

1. HZ 配置

HZ 是内核定时器中断的频率,定义在kernel/Kconfig.hz

choice prompt"Timer frequency"defaultHZ_250 config HZ_100 bool"100 HZ"// 服务器,10ms 中断config HZ_250 bool"250 HZ"// 桌面/服务器平衡,4ms 中断config HZ_300 bool"300 HZ"// 多媒体,3.33ms 中断config HZ_1000 bool"1000 HZ"// 桌面,1ms 中断

RK3588 默认 HZ = 250(每 4ms 一次定时器中断)

2. timer_list 结构

// include/linux/timer.hstructtimer_list{structhlist_nodeentry;// 链表节点unsignedlongexpires;// 到期时间 (jiffies)void(*function)(structtimer_list*);// 回调函数u32 flags;// 标志位// ...};

3. 传统定时器中断处理

tick_periodic()- kernel/time/tick-common.c:84

staticvoidtick_periodic(intcpu){// 1. 更新系统时间if(tick_do_timer_cpu==cpu){raw_spin_lock(&jiffies_lock);write_seqcount_begin(&jiffies_seq);// 计算下一个 tick 时间tick_next_period=ktime_add_ns(tick_next_period,TICK_NSEC);do_timer(1);// 更新 jiffieswrite_seqcount_end(&jiffies_seq);raw_spin_unlock(&jiffies_lock);update_wall_time();// 更新墙钟时间}// 2. 更新进程统计update_process_times(user_mode(get_irq_regs()));// 3. 更新调度器统计profile_tick(CPU_PROFILING);}

4. 传统定时器 API

// 定义并初始化定时器DEFINE_TIMER(my_timer,my_timer_callback);// 或运行时初始化structtimer_listmy_timer;timer_setup(&my_timer,my_timer_callback,0);// 启动定时器 (在 expires jiffies 后到期)mod_timer(&my_timer,jiffies+msecs_to_jiffies(100));// 取消定时器del_timer(&my_timer);

5. 时间轮算法

传统定时器使用时间轮算法组织定时器 (kernel/time/timer.c):

时间轮结构 (LVL_DEPTH = 9): Level 0: 64 buckets × 1ms = 0-63ms (HOT) Level 1: 64 buckets × 8ms = 64-511ms Level 2: 64 buckets × 64ms = 512ms-4s Level 3: 64 buckets × 512ms = 4s-32s Level 4: 64 buckets × 4s = 32s-4m Level 5: 64 buckets × 32s = 4m-34m Level 6: 64 buckets × 256s = 34m-4h Level 7: 64 buckets × 34m = 4h-1d Level 8: 64 buckets × 4h = 1d-12d (COLD)

高精度定时器 (hrtimer)

1. hrtimer 结构

// include/linux/hrtimer.hstructhrtimer{structtimerqueue_nodenode;// 时间堆节点ktime_t_softexpires;// 最早到期时间enumhrtimer_restart(*function)(structhrtimer*);// 回调structhrtimer_clock_base*base;// 指向定时器基u8 state;// 状态位u8 is_rel;// 是否相对时间u8 is_soft;// 软中断上下文u8 is_hard;// 硬中断上下文};

2. hrtimer 中断处理

tick_sched_timer()- kernel/time/tick-sched.c

staticenumhrtimer_restarttick_sched_timer(structhrtimer*timer){structtick_sched*ts=container_of(timer,structtick_sched,sched_timer);structpt_regs*regs=get_irq_regs();ktime_tnow=ktime_get();// 1. 更新 jiffiestick_sched_do_timer(ts,now);// 2. 更新进程统计update_process_times(user_mode(regs));// 3. 重新编程下一个 tick// (如果是 NOHZ 模式,可能跳过)hrtimer_forward(timer,now,tick_period);returnHRTIMER_RESTART;}

3. hrtimer API

// 定义 hrtimerstructhrtimermy_hrtimer;// 初始化hrtimer_init(&my_hrtimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);// 设置回调my_hrtimer.function=my_hrtimer_callback;// 启动高精度定时器 (1000 纳秒后到期)hrtimer_start(&my_hrtimer,ns_to_ktime(1000),HRTIMER_MODE_REL);// 取消定时器hrtimer_cancel(&my_hrtimer);

4. hrtimer 红黑树组织

hrtimer_cpu_base | ┌─────────────┼─────────────┐ │ │ │ clock_base[0] clock_base[1] clock_base[2] (MONOTONIC) (REALTIME) (BOOTTIME) │ ├─ 红黑树 (按到期时间排序) │ ├─ earliest timer ←── 最快到期的定时器 │ └─ next timer 硬件定时器被编程为 earliest 的到期时间

两种定时器的关系

关键问题:HZ 定时器和 hrtimer 是同一个吗?

答案:不是同一个,但它们共享硬件定时器。

1. 工作模式

内核可以在两种模式下工作:

模式 A: 周期 tick 模式 (低分辨率)
┌─────────────────────────────────────────────────────────────┐ │ 周期 Tick 模式 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 每 4ms (HZ=250) 触发一次硬件定时器中断 │ │ ↓ │ │ tick_periodic() │ │ ↓ │ │ ├─ do_timer() → 更新 jiffies │ │ ├─ update_wall_time() → 更新墙钟 │ │ └─ update_process_times() → 更新进程统计 │ │ │ │ timer_list 定时器在软中断中检查并处理 │ │ │ └─────────────────────────────────────────────────────────────┘ 时间轴: 0ms ──→ 4ms ──→ 8ms ──→ 12ms ──→ 16ms ... tick tick tick tick
模式 B: 高精度模式 (NOHZ + 高分辨率)
┌─────────────────────────────────────────────────────────────┐ │ 高精度模式 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 硬件定时器按需触发 (基于下一个 hrtimer 到期时间) │ │ ↓ │ │ tick_sched_timer() [hrtimer 中断] │ │ ↓ │ │ ├─ tick_sched_do_timer() → 更新 jiffies │ │ ├─ hrtimer_interrupt() → 处理到期的 hrtimer │ │ └─ update_process_times() → 更新进程统计 │ │ │ │ 动态编程下一个事件,可能是 1ms 后或 100ms 后 │ │ │ └─────────────────────────────────────────────────────────────┘ 时间轴: 0ms ──────→ 1ms ───→ 1.5ms ─────────→ 10ms ──→ ... hrtimer1 hrtimer2 idle hrtimer3

2. 模式切换流程

// 启动时tick_init()tick_setup_device()// 根据 CPU 特性选择模式if(arch_timer_has_c3stop||highres_requested){// 使用高精度模式tick_setup_sched_timer(newdev);}else{// 使用周期 tick 模式tick_setup_periodic(newdev,0);}

3. 共享硬件定时器

关键点:两种模式使用同一个硬件定时器 (ARM 架构定时器)

// drivers/clocksource/arm_arch_timer.c:807clockevents_config_and_register(clk,arch_timer_rate,0xf,0x7fffffff);// ↑// 注册为时钟事件设备// 被 tick 设备层使用

流程:

┌─────────────────────────────────────────────────────────────┐ │ 硬件定时器 (ARM 架构定时器) │ │ │ │ arch_timer_set_next_event_virt(evt, clk) │ │ ↓ │ │ 写 CNTV_TVAL_EL0 寄存器 │ │ ↓ │ │ 硬件在指定时间触发中断 │ │ ↓ │ │ 中断发生 │ │ ↓ │ ├─────────────────────────────────────────────────────────────┤ │ 根据当前模式调用不同的中断处理函数: │ │ │ │ 周期模式: tick_periodic() │ │ 高精度模式: tick_sched_timer() │ │ │ └─────────────────────────────────────────────────────────────┘

4. 实际中断处理流程

// 硬件中断 → clock_event_device → tick 设备// 1. 硬件中断处理arch_timer_handler_virt(intirq,void*dev_id){structclock_event_device*evt=dev_id;// 调用 clock_event_device 注册的处理函数evt->event_handler(evt);// event_handler 可能是:// - tick_handle_periodic() → 周期模式// - hrtimer_interrupt() → 高精度模式}// 2. 周期模式处理tick_handle_periodic(structclock_event_device*dev){tick_periodic(smp_processor_id());// 然后硬件会自动周期触发 (如果支持)}// 3. 高精度模式处理hrtimer_interrupt(structclock_event_device*dev){// 找到所有到期的 hrtimer 并执行回调__hrtimer_run_queues();// 重新编程下一个事件hrtimer_reprogram();}

硬件定时器层

ARM 架构定时器寄存器

┌─────────────────────────────────────────────────────────────┐ │ ARMv8 架构定时器 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 系统计数器 (CNTVCT_EL0): │ │ • 全局单调递增计数器 │ │ • 24MHz 频率 │ │ • 56 位有效宽度 │ │ │ │ 定时器控制寄存器: │ │ • CNTV_CTL_EL0 - 虚拟定时器控制 │ │ • CNTV_TVAL_EL0 - 虚拟定时器比较值 │ │ • CNTV_CVAL_EL0 - 虚拟定时器绝对值 │ │ │ │ 工作原理: │ │ 当 CNTVCT >= CNTV_CVAL 时触发中断
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/12 12:51:30

CUDA安装Nsight Systems性能分析工具介绍

CUDA与Nsight Systems在AI开发中的性能优化实践 如今,深度学习模型的规模正以惊人的速度增长——从数亿参数到数千亿参数,训练任务对算力的需求几乎每两年翻一番。在这种背景下,仅仅让代码“跑起来”已经远远不够了。我们真正需要的是高效地跑…

作者头像 李华
网站建设 2026/4/16 15:06:26

Miniconda-Python3.10一键配置PyTorch环境,轻松实现AI训练加速

Miniconda-Python3.10一键配置PyTorch环境,轻松实现AI训练加速 在高校实验室里,一个学生刚接手师兄留下的深度学习项目,满怀信心地运行代码,结果却卡在了第一条 import torch 上——CUDA 版本不兼容、依赖包冲突、环境变量错误………

作者头像 李华
网站建设 2026/4/16 13:32:59

嵌入式系统中crash的底层驱动成因深度剖析

嵌入式系统崩溃的底层驱动真相:从指针越界到中断失控,一次讲透你有没有遇到过这样的场景?设备运行得好好的,突然“啪”一下重启,串口只留下一行模糊的Unable to handle kernel NULL pointer dereference,再…

作者头像 李华
网站建设 2026/4/16 15:15:14

WeChatPad终极指南:轻松实现微信多设备同时在线

WeChatPad终极指南:轻松实现微信多设备同时在线 【免费下载链接】WeChatPad 强制使用微信平板模式 项目地址: https://gitcode.com/gh_mirrors/we/WeChatPad 微信作为国民级应用,其设备限制一直是用户痛点。WeChatPad项目通过创新的技术方案&…

作者头像 李华
网站建设 2026/4/16 15:15:12

终极指南:WeChatPad如何强制开启微信平板模式实现双设备登录

终极指南:WeChatPad如何强制开启微信平板模式实现双设备登录 【免费下载链接】WeChatPad 强制使用微信平板模式 项目地址: https://gitcode.com/gh_mirrors/we/WeChatPad WeChatPad是一款基于Xposed框架的LSPosed模块,专门用于强制启用微信平板模…

作者头像 李华
网站建设 2026/4/16 13:44:35

微信平板模式消失的终极解决方案:WeChatPad项目深度解析

微信平板模式消失的终极解决方案:WeChatPad项目深度解析 【免费下载链接】WeChatPad 强制使用微信平板模式 项目地址: https://gitcode.com/gh_mirrors/we/WeChatPad 当微信更新到8.0.48版本后,许多用户惊讶地发现平板模式的关键功能神秘消失&…

作者头像 李华