本页目录

时钟与定时器

覆盖: timer wheel → hrtimer (红黑树) → clockevent/clocksource → tick (periodic/dyntick/nohz) → POSIX timer → itimer 内核版本: 2.6 ~ 6.x

概述

内核中有两套定时器系统共存:

  • timer wheel (低精度): jiffy 粒度 (1/HZ 秒, 通常 1ms/4ms), mod_timer()/del_timer()
  • hrtimer (高精度): 纳秒级, 红黑树排序, hrtimer_start()/hrtimer_cancel()

这一双轨设计源自历史:timer wheel 是原始实现,hrtimer 是 2.6.16 引入的精确替代。现在两者共存——timer wheel 处理低精度大量定时器(如网络超时),hrtimer 处理精确事件(如 POSIX timer、tick 模拟)。


Jiffies 与 HZ

// include/linux/jiffies.h
extern unsigned long volatile jiffies;  // 自启动以来的 tick 数

// HZ = 每秒的 tick 数 (内核编译时配置):
//   CONFIG_HZ=100   → 10ms 精度 (服务器, 低 CPU 开销)
//   CONFIG_HZ=250   → 4ms 精度 (默认)
//   CONFIG_HZ=1000  → 1ms 精度 (桌面/实时, 更平滑但更多中断)

// jiffies wrap:
//   32-bit: 2^32 / HZ ≈ 497 天 (HZ=100)
//   64-bit: wrap 大于宇宙寿命
//   time_after(a, b) / time_before(a, b) 宏处理 wrap 比较

Timer Wheel: 低精度定时器

// kernel/time/timer.c
// 按到期时间分桶 (类似水钟)
// 桶大小: 1 jiffy, 8 jiffies, 64 jiffies, 512 jiffies, ...

struct timer_list {
    unsigned long       expires;      // 到期 jiffies
    void                (*function)(struct timer_list *);
    u32                 flags;
};

// 注册:
mod_timer(&timer, jiffies + msecs_to_jiffies(500)); // 500ms 后触发

// 删除:
del_timer(&timer);         // 同步删除
del_timer_sync(&timer);    // 等待可能正在运行的 handler 完成

// 定时器在 softirq 上下文运行 (TIMER_SOFTIRQ)
// → 不能睡眠, 不能拿 mutex

hrtimer: 高精度定时器

// kernel/time/hrtimer.c
// 纳秒级精度, 红黑树排序
// 需要硬件支持 (HPET, TSC, 或 APIC timer)

struct hrtimer {
    ktime_t             expires;        // 绝对到期时间 (ktime_t, ns)
    enum hrtimer_restart (*function)(struct hrtimer *);
};

// 使用:
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer.function = my_callback;
hrtimer_start(&timer, ns_to_ktime(1000000), HRTIMER_MODE_REL);
// → 1ms 后回调

// hrtimer 到期 → 在中断上下文中回调 (HRTIMER_SOFTIRQ)
// 如果需要睡眠 → 使用 schedule_hrtimeout()

Clock Event 与 Clock Source

// kernel/time/clockevents.c + kernel/time/clocksource.c
// clocksource: 提供当前时间 (抽象了 TSC, HPET, ACPI PM timer)
//   read() → 返回 cycle_t (monotonic counter)
//   → 通过 mult/shift 转换为纳秒

// clockevent: 提供未来事件编程 (抽象了 Local APIC timer, HPET)
//   set_next_event(delta_ns) → 编程硬件在 delta_ns 后产生中断
//   → 这是 tick 和 hrtimer 的硬件基础

// tick device:
//   每个 CPU 有一个 clockevent 作为 tick device
//   可以是 per-CPU (Local APIC timer) 或全局 broadcast (HPET)

Tick 管理: periodic / dyntick / nohz

// 三种 tick 模式:

// 1. Periodic tick (旧):
//    每个 CPU 每 1/HZ 秒产生一次 timer interrupt
//    → 用于更新时间 (jiffies), 调度器 tick, 进程统计
//    → 但大部分 tick 是浪费的 (CPU idle 时不需要 tick)

// 2. Dynamic tick (dyntick / CONFIG_NO_HZ_IDLE, 2.6.21+):
//    当 CPU idle 时: 停止 tick → CPU 进入深度睡眠 (C-state)
//    → 根据下一个定时器到期时间编程 clockevent 一次性唤醒
//    → 节能: 每瓦特跑更多工作

// 3. Full nohz (CONFIG_NO_HZ_FULL, 3.10+):
//    当 CPU 只有一个可运行任务时: 停止 tick
//    → 减少 tick 中断对延迟敏感任务 (HPC/实时) 的干扰
//    → 但 RCU 和 sched 统计需要 adapt → 更复杂

POSIX Timer 与 itimer

// kernel/time/posix-timers.c
// 用户态定时器 API:

// POSIX timer (per-process):
timer_create(CLOCK_MONOTONIC, &evp, &timerid);
timer_settime(timerid, 0, &its, NULL);
// → 内核创建 hrtimer → 到期时发信号 (SIGALRM, SIGEV_SIGNAL)

// POSIX interval timer (itimer):
setitimer(ITIMER_REAL, &value, NULL);  // SIGALRM
setitimer(ITIMER_VIRTUAL, &value, NULL);  // SIGVTALRM (仅用户态时间)
setitimer(ITIMER_PROF, &value, NULL);  // SIGPROF (用户+内核时间)

// timerfd (2.6.25+):
int fd = timerfd_create(CLOCK_MONOTONIC, 0);
timerfd_settime(fd, 0, &its, NULL);
// → fd 可读 → 定时器到期 (可 poll/epoll, 极方便)

调试

# 当前 tick 模式
cat /sys/devices/system/cpu/cpu0/cpuidle/state*/disable

# timer wheel 统计 (/proc/timer_list)
cat /proc/timer_list | head -100

# hrtimer 统计
cat /proc/timer_list | grep -A5 hrtimer

# HZ 值
getconf CLK_TCK          # 用户态 HZ
grep CONFIG_HZ /boot/config-$(uname -r)  # 内核编译时 HZ

参考与延伸

  • 内核文档⁠: Documentation/timers/
  • LWN: "The timer wheel", "hrtimers and the tick", "NOHZ full"
  • 源码⁠:
    • kernel/time/timer.c — timer wheel
    • kernel/time/hrtimer.c — hrtimer
    • kernel/time/tick-common.c — tick 管理
    • kernel/time/tick-sched.c — dyntick/nohz
    • kernel/time/clocksource.c — clocksource
    • kernel/time/clockevents.c — clockevent
    • kernel/time/posix-timers.c — POSIX timer

关键词: timer wheel, hrtimer, jiffies, HZ, clockevent, clocksource, dyntick, nohz, POSIX timer, timerfd