Skip to content

Linux 内核时间子系统深度分析文档 R1 ​

目录 ​

  1. Tick Device 子系统
  2. Clockevent 设备
  3. Timekeeping 核心
  4. Hrtimer 调度
  5. Posix Timer 机制
  6. 性能优化

1. Tick Device 子系统 ​

1.1 tick_device 结构详解 ​

文件位置: /Users/sphinx/github/linux/kernel/time/tick-sched.h

c
enum tick_device_mode {
    TICKDEV_MODE_PERIODIC,    // 周期模式
    TICKDEV_MODE_ONESHOT,     // 单次触发模式
};

struct tick_device {
    struct clock_event_device *evtdev;  // 指向 clock event 设备
    enum tick_device_mode mode;         // 设备模式
};

关键特性:

  • 每个 CPU 有一个 tick_device 实例 (DEFINE_PER_CPU(struct tick_device, tick_cpu_device))
  • evtdev 指向该 CPU 的时钟事件设备
  • mode 决定是周期模式还是单次触发模式

1.2 tick_sched 结构与动态 tick ​

文件位置: /Users/sphinx/github/linux/kernel/time/tick-sched.h 第 33-103 行

c
struct tick_sched {
    /* 状态标志 - TS_FLAG_* */
    unsigned long           flags;

    /* jiffies 失速检测 */
    unsigned int           stalled_jiffies;
    unsigned long          last_tick_jiffies;

    /* 调度定时器 - 用于 NOHZ 模式 */
    struct hrtimer         sched_timer;    // 周期性 tick 的 hrtimer 模拟
    ktime_t                last_tick;      // 上一次 tick 时间
    ktime_t                next_tick;      // 下一次 tick 时间

    /* Idle 时间统计 */
    unsigned long          idle_jiffies;
    ktime_t                idle_waketime;
    unsigned int           got_idle_tick;

    /* Tick 停止相关 */
    unsigned long          last_jiffies;
    u64                     timer_expires_base;
    u64                     timer_expires;
    u64                     next_timer;
    ktime_t                 idle_expires;

    /* Idle 退出统计 */
    ktime_t                idle_exittime;
    ktime_t                idle_sleeptime;
    ktime_t                iowait_sleeptime;

    /* NOHZ_FULL 支持 */
    atomic_t               tick_dep_mask;  // Tick 依赖掩码

    /* 时钟源变化通知 */
    unsigned long          check_clocks;
};

状态标志 (TS_FLAG_*):

c
#define TS_FLAG_INIDLE       BIT(0)  // CPU 处于 idle 模式
#define TS_FLAG_STOPPED      BIT(1)  // Tick 已停止
#define TS_FLAG_IDLE_ACTIVE BIT(2)  // Idle tick 已激活
#define TS_FLAG_DO_TIMER_LAST BIT(3) // 最后执行 do_timer 的 CPU
#define TS_FLAG_NOHZ        BIT(4)  // NO_HZ 已启用
#define TS_FLAG_HIGHRES     BIT(5)  // 高精度 tick 模式

1.3 tick_handle_periodic vs tick_handle_periodic_broadcast ​

tick_handle_periodic (tick-common.c 第 108-146 行):

c
void tick_handle_periodic(struct clock_event_device *dev)
{
    int cpu = smp_processor_id();
    ktime_t next = dev->next_event;

    tick_periodic(cpu);  // 处理周期 tick

    // 如果切换到 HIGHRES/NOHZ 模式,直接返回
    if (IS_ENABLED(CONFIG_TICK_ONESHOT) && dev->event_handler != tick_handle_periodic)
        return;

    if (!clockevent_state_oneshot(dev))
        return;

    // Oneshot 模式:重新编程下一个事件
    for (;;) {
        next = ktime_add_ns(next, TICK_NSEC);
        if (!clockevents_program_event(dev, next, false))
            return;
        // 防止硬件时钟源无效导致的无限循环
        if (timekeeping_valid_for_hres())
            tick_periodic(cpu);
    }
}

核心流程:

  1. 调用 tick_periodic() 处理周期 tick
  2. 检查是否切换到其他模式
  3. 在 ONESHOT 模式下循环重新编程

1.4 NO_HZ vs HIGH_RES_TICK ​

NO_HZ (动态 tick):

在 tick-sched.c 中实现,核心函数:

c
// tick-sched.c 第 922-998 行
static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
{
    u64 basemono, next_tick, delta, expires;
    unsigned long basejiff;
    int tick_cpu;

    basemono = get_jiffies_update(&basejiff);
    ts->last_jiffies = basejiff;
    ts->timer_expires_base = basemono;

    // 检查是否需要保持 tick (RCU、架构、irq_work 请求)
    if (rcu_needs_cpu() || arch_needs_cpu() ||
        irq_work_needs_cpu() || local_timer_softirq_pending()) {
        next_tick = basemono + TICK_NSEC;
    } else {
        // 获取下一个定时器中断时间
        next_tick = get_next_timer_interrupt(basejiff, basemono);
        ts->next_timer = next_tick;
    }

    // 根据 tick 依赖决定是否停止 tick
    delta = next_tick - basemono;
    if (delta <= (u64)TICK_NSEC) {
        if (!tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
            ts->timer_expires = 0;
            goto out;
        }
    }

    // 限制最大延迟
    delta = timekeeping_max_deferment();
    tick_cpu = READ_ONCE(tick_do_timer_cpu);
    if (tick_cpu != cpu &&
        (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
        delta = KTIME_MAX;

    // 计算过期时间
    expires = basemono + delta;
    ts->timer_expires = min_t(u64, expires, next_tick);

out:
    return ts->timer_expires;
}

HIGH_RES_TICK (高精度 tick):

在 hrtimer.c 中实现,核心函数 hrtimer_switch_to_hres():

c
// hrtimer.c 第 738-753 行
static void hrtimer_switch_to_hres(void)
{
    struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);

    if (tick_init_highres()) {  // 切换到高精度模式
        pr_warn("Could not switch to high resolution mode on CPU %u\n",
                base->cpu);
        return;
    }
    base->hres_active = 1;  // 标记高精度模式活跃
    hrtimer_resolution = HIGH_RES_NSEC;

    tick_setup_sched_timer(true);  // 设置调度定时器
    retrigger_next_event(NULL);    // 重新触发下一个事件
}

2. Clockevent 设备 ​

2.1 struct clock_event_device 完整字段 ​

文件位置: /Users/sphinx/github/linux/include/linux/clockchips.h 第 100-132 行

c
struct clock_event_device {
    // 事件处理回调
    void            (*event_handler)(struct clock_event_device *);

    // 设置下一个事件的函数指针
    int             (*set_next_event)(unsigned long evt, struct clock_event_device *);
    int             (*set_next_ktime)(ktime_t expires, struct clock_event_device *);

    // 下一个事件时间(ktime 格式)
    ktime_t         next_event;

    // 最小/最大 delta (纳秒)
    u64             max_delta_ns;   // 最大延迟
    u64             min_delta_ns;   // 最小延迟

    // 乘数和移位因子 (用于 scaled math)
    u32             mult;           // 纳秒转 cycles 的乘数
    u32             shift;          // 纳秒转 cycles 的除数 (2^shift)

    // 当前状态
    enum clock_event_state state_use_accessors;

    // 特性标志
    unsigned int    features;

    // 重试计数
    unsigned long   retries;

    // 状态切换回调
    int             (*set_state_periodic)(struct clock_event_device *);
    int             (*set_state_oneshot)(struct clock_event_device *);
    int             (*set_state_oneshot_stopped)(struct clock_event_device *);
    int             (*set_state_shutdown)(struct clock_event_device *);
    int             (*tick_resume)(struct clock_event_device *);

    // 广播函数
    void            (*broadcast)(const struct cpumask *mask);

    // 挂起/恢复回调
    void            (*suspend)(struct clock_event_device *);
    void            (*resume)(struct clock_event_device *);

    // Tick 值范围
    unsigned long   min_delta_ticks;
    unsigned long   max_delta_ticks;

    // 设备信息
    const char      *name;
    int             rating;         // 设备评分,用于选择最佳设备
    int             irq;            // IRQ 号
    int             bound_on;       // 绑定的 CPU
    const struct cpumask *cpumask;  // 支持的 CPU 掩码

    // 链表头
    struct list_head        list;
    struct module          *owner;
};

设备状态枚举 (clockchips.h 第 35-41 行):

c
enum clock_event_state {
    CLOCK_EVT_STATE_DETACHED,      // 未使用
    CLOCK_EVT_STATE_SHUTDOWN,     // 关闭
    CLOCK_EVT_STATE_PERIODIC,     // 周期模式
    CLOCK_EVT_STATE_ONESHOT,      // 单次触发
    CLOCK_EVT_STATE_ONESHOT_STOPPED, // 单次触发已停止
};

设备特性 (clockchips.h 第 46-57 行):

c
#define CLOCK_EVT_FEAT_PERIODIC    0x000001  // 支持周期模式
#define CLOCK_EVT_FEAT_ONESHOT     0x000002  // 支持单次触发
#define CLOCK_EVT_FEAT_KTIME       0x000004  // 支持直接 ktime 设置
#define CLOCK_EVT_FEAT_C3STOP      0x000008  // C3 停止时需要广播
#define CLOCK_EVT_FEAT_DUMMY       0x000010  // 虚拟设备

2.2 clockevents_register_device() 注册流程 ​

文件位置: /Users/sphinx/github/linux/kernel/time/clockevents.c 第 451-476 行

c
void clockevents_register_device(struct clock_event_device *dev)
{
    unsigned long flags;

    // 1. 初始化状态为 DETACHED
    clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED);

    // 2. 如果没有设置 cpumask,默认为当前 CPU
    if (!dev->cpumask) {
        WARN_ON(num_possible_cpus() > 1);
        dev->cpumask = cpumask_of(smp_processor_id());
    }

    // 3. 防止 cpumask 设置为 cpu_all_mask
    if (dev->cpumask == cpu_all_mask) {
        dev->cpumask = cpu_possible_mask;
    }

    raw_spin_lock_irqsave(&clockevents_lock, flags);

    // 4. 添加到全局设备链表
    list_add(&dev->list, &clockevent_devices);

    // 5. 检查是否可以替换当前 CPU 的 tick 设备
    tick_check_new_device(dev);

    // 6. 处理被释放的设备
    clockevents_notify_released();

    raw_spin_unlock_irqrestore(&clockevents_lock, flags);
}

关键数据结构:

c
static LIST_HEAD(clockevent_devices);      // 已注册设备链表
static LIST_HEAD(clockevents_released);    // 已释放设备链表
static DEFINE_RAW_SPINLOCK(clockevents_lock);  // 保护链表

2.3 tickdev 模式 vs clockevent芯片模式 ​

tickdev 模式 (Tick Device 模式):

  • 由内核软件管理 tick,使用 clockevent 设备的单次触发能力
  • 每次到期后重新编程
  • 支持 NO_HZ 和动态 tick

clockevent芯片模式:

  • 硬件自己管理周期中断
  • 内核只负责设置周期频率
  • 不能动态调整 tick 间隔

3. Timekeeping 核心 ​

3.1 struct timekeeper 完整结构 ​

文件位置: /Users/sphinx/github/linux/include/linux/timekeeper_internal.h 第 140-183 行

c
struct timekeeper {
    /* Cacheline 0 (与 seqcount 一起) */
    struct tk_read_base    tkr_mono;        // CLOCK_MONOTONIC 读取基址

    /* Cacheline 1 */
    u64             xtime_sec;              // CLOCK_REALTIME 秒数
    unsigned long   ktime_sec;              // CLOCK_MONOTONIC 秒数
    struct timespec64 wall_to_monotonic;   // Realtime 到 Monotonic 的偏移
    ktime_t         offs_real;             // Monotonic -> Realtime 偏移
    ktime_t         offs_boot;             // Monotonic -> Boottime 偏移
    union {
        ktime_t     offs_tai;               // Monotonic -> TAI 偏移
        ktime_t     offs_aux;               // Monotonic -> AUX 偏移
    };
    u32             coarse_nsec;            // 粗粒度时间纳秒部分
    enum timekeeper_ids id;                // Timekeeper ID

    /* Cacheline 2 */
    struct tk_read_base    tkr_raw;         // CLOCK_MONOTONIC_RAW 读取基址
    u64             raw_sec;                // Raw 时间秒数

    /* Cacheline 3-4 (内部变量) */
    unsigned int    clock_was_set_seq;     // clock_was_set 事件序列号
    u8              cs_was_changed_seq;    // 时钟源变更序列号
    u8              clock_valid;            // 时钟有效标志

    union {
        struct timespec64 monotonic_to_boot;
        struct timespec64 monotonic_to_aux;
    };

    u64             cycle_interval;         // 一个 NTP 周期的时钟周期数
    u64             xtime_interval;         // 一个 NTP 周期的纳秒数(移位后)
    s64             xtime_remainder;        // 剩余未分配的纳秒
    u64             raw_interval;           // Raw 时间间隔

    ktime_t         next_leap_ktime;       // 下一次闰秒时间
    u64             ntp_tick;              // NTP tick 长度
    s64             ntp_error;             // NTP 累积误差
    u32             ntp_error_shift;       // 误差移位转换
    u32             ntp_err_mult;          // 误差乘数
    u32             skip_second_overflow;   // 跳过第二次溢出标志
    s32             tai_offset;            // UTC 到 TAI 的偏移
};

tk_read_base 结构 (timekeeper_internal.h 第 50-59 行):

c
struct tk_read_base {
    struct clocksource  *clock;             // 当前使用的时钟源
    u64                 mask;                // 两补码减法的掩码
    u64                 cycle_last;          // 上次读取的时钟周期值
    u32                 mult;                // (NTP 调整后的)乘数
    u32                 shift;               // 移位值
    u64                 xtime_nsec;          // 移位的纳秒偏移
    ktime_t             base;                // 读取基址(纳秒)
    u64                 base_real;           // CLOCK_REALTIME 的纳秒基址
};

3.2 tk_core vs timekeeper 关系 ​

文件位置: /Users/sphinx/github/linux/kernel/time/timekeeping.c 第 52-62 行

c
struct tk_data {
    seqcount_raw_spinlock_t     seq;           // 序列计数器
    struct timekeeper           timekeeper;     // 主 timekeeper
    struct timekeeper           shadow_timekeeper; // 影子 timekeeper
    raw_spinlock_t              lock;           // 保护锁
} ____cacheline_aligned;

static struct tk_data timekeeper_data[TIMEKEEPERS_MAX];

/* 核心 timekeeper - 全局访问点 */
#define tk_core (timekeeper_data[TIMEKEEPER_CORE])

设计模式 - Shadow Timekeeper:

  1. 所有更新先写入 shadow_timekeeper
  2. 验证通过后才拷贝到 timekeeper
  3. 这样读者可以无锁访问 timekeeper,写入时才加锁

3.3 update_wall_time() 详细流程 ​

文件位置: /Users/sphinx/github/linux/kernel/time/timekeeping.c 第 2388-2398 行

c
void update_wall_time(void)
{
    if (timekeeping_advance(TK_ADV_TICK))
        clock_was_set_delayed();
    tk_aux_advance();
}

核心更新流程 (__timekeeping_advance, 第 2321-2380 行):

c
static bool __timekeeping_advance(struct tk_data *tkd, enum timekeeping_adv_mode mode)
{
    struct timekeeper *tk = &tkd->shadow_timekeeper;
    struct timekeeper *real_tk = &tkd->timekeeper;
    unsigned int clock_set = 0;
    int shift = 0, maxshift;
    u64 offset, orig_offset;

    // 如果 timekeeping 已挂起,直接返回
    if (unlikely(timekeeping_suspended))
        return false;

    // 读取当前时钟源周期增量
    offset = clocksource_delta(tk_clock_read(&tk->tkr_mono),
                              tk->tkr_mono.cycle_last, tk->tkr_mono.mask,
                              tk->tkr_mono.clock->max_raw_delta);
    orig_offset = offset;

    // 如果没有超过一个周期,无事可做
    if (offset < real_tk->cycle_interval && mode == TK_ADV_TICK)
        return false;

    // 对数累积 - 一次性累积多个周期
    shift = ilog2(offset) - ilog2(tk->cycle_interval);
    shift = max(0, shift);
    maxshift = (64 - (ilog2(ntp_tick_length(tk->id)) + 1)) - 1;
    shift = min(shift, maxshift);

    while (offset >= tk->cycle_interval) {
        offset = logarithmic_accumulation(tk, offset, shift, &clock_set);
        if (offset < tk->cycle_interval<<shift)
            shift--;
    }

    // 调整乘数以纠正 NTP 误差
    timekeeping_adjust(tk, offset);

    // 确保 xtime_nsec 不超过 NSEC_PER_SEC
    clock_set |= accumulate_nsecs_to_secs(tk);

    // 如果有原始偏移更新,更新粗粒度时钟
    if (orig_offset != offset)
        tk_update_coarse_nsecs(tk);

    // 从 shadow 拷贝到 real timekeeper
    timekeeping_update_from_shadow(tkd, clock_set);

    return !!clock_set;
}

3.4 NTP 调整机制 ​

ntp_tick_length 返回每个 tick 的精确长度,考虑 NTP 调整:

c
// ntp_internal.h 第 8 行
extern u64 ntp_tick_length(unsigned int tkid);

NTP 调整流程 (timekeeping_adjust, 第 2172-2225 行):

c
static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
{
    u64 ntp_tl = ntp_tick_length(tk->id);
    u32 mult;

    // 从 ntp_tick_length 获取当前的 tick 长度
    if (likely(tk->ntp_tick == ntp_tl)) {
        mult = tk->tkr_mono.mult - tk->ntp_err_mult;
    } else {
        tk->ntp_tick = ntp_tl;
        mult = div64_u64((tk->ntp_tick >> tk->ntp_error_shift) -
                         tk->xtime_remainder, tk->cycle_interval);
    }

    // NTP 误差修正
    tk->ntp_err_mult = tk->ntp_error > 0 ? 1 : 0;
    mult += tk->ntp_err_mult;

    // 应用调整
    timekeeping_apply_adjustment(tk, offset, mult - tk->tkr_mono.mult);
}

4. Hrtimer 调度 ​

4.1 hrtimer_cpu_base 层次结构 ​

文件位置: /Users/sphinx/github/linux/include/linux/hrtimer_defs.h 第 81-107 行

c
struct hrtimer_cpu_base {
    raw_spinlock_t          lock;           // 保护锁
    unsigned int            cpu;             // CPU 编号
    unsigned int            active_bases;    // 有活跃定时器的基址位域
    unsigned int            clock_was_set_seq; // clock_was_set 序列号

    // 状态标志
    unsigned int            hres_active     : 1,  // 高精度模式活跃
                            in_hrtirq       : 1,  // 正在执行 hrtimer 中断
                            hang_detected   : 1,  // 检测到中断挂起
                            softirq_activated : 1, // 软中断已激活
                            online          : 1;  // CPU 在线

#ifdef CONFIG_HIGH_RES_TIMERS
    unsigned int            nr_events;      // 中断事件总数
    unsigned short          nr_retries;     // 重试次数
    unsigned short          nr_hangs;       // 挂起次数
    unsigned int            max_hang_time;  // 最大挂起时间
#endif

#ifdef CONFIG_PREEMPT_RT
    spinlock_t              softirq_expiry_lock; // 软中断到期锁
    atomic_t                timer_waiters;       // 等待定时器的数量
#endif

    ktime_t                 expires_next;    // 下一个事件时间(绝对时间)
    struct hrtimer          *next_timer;    // 下一个到期的定时器
    ktime_t                 softirq_expires_next; // 软中断下一个到期时间
    struct hrtimer          *softirq_next_timer; // 软中断下一个到期定时器

    struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; // 时钟基址数组
    call_single_data_t      csd;            // 跨 CPU 调用数据
};

hrtimer_clock_base 结构 (hrtimer_defs.h 第 26-34 行):

c
struct hrtimer_clock_base {
    struct hrtimer_cpu_base *cpu_base;      // 指向父 CPU 基址
    unsigned int            index;           // 基址索引
    clockid_t              clockid;         // 时钟 ID
    seqcount_raw_spinlock_t seq;            // 序列计数器
    struct hrtimer         *running;         // 当前运行的定时器
    struct timerqueue_head  active;          // 活跃定时器红黑树
    ktime_t                 offset;         // 到 monotonic 的偏移
};

时钟基址类型 (hrtimer_defs.h 第 36-46 行):

c
enum hrtimer_base_type {
    HRTIMER_BASE_MONOTONIC,      // CLOCK_MONOTONIC
    HRTIMER_BASE_REALTIME,      // CLOCK_REALTIME
    HRTIMER_BASE_BOOTTIME,     // CLOCK_BOOTTIME
    HRTIMER_BASE_TAI,          // CLOCK_TAI
    HRTIMER_BASE_MONOTONIC_SOFT, // CLOCK_MONOTONIC (软中断)
    HRTIMER_BASE_REALTIME_SOFT,  // CLOCK_REALTIME (软中断)
    HRTIMER_BASE_BOOTTIME_SOFT, // CLOCK_BOOTTIME (软中断)
    HRTIMER_BASE_TAI_SOFT,     // CLOCK_TAI (软中断)
    HRTIMER_MAX_CLOCK_BASES,
};

4.2 红黑树 vs 链表组织 ​

定时器队列 - 使用 timerqueue_head (红黑树):

c
// 每个 hrtimer_clock_base 有一个 active 队列
struct timerqueue_head {
    struct rb_root_cached   head;  // 红黑树根节点
    struct rb_node          *leftmost; // 最左侧节点(最近到期)
};

定时器节点 - timerqueue_node:

c
struct timerqueue_node {
    struct rb_node          node;   // 红黑树节点
    ktime_t                 expires; // 到期时间
};

hrtimer 结构 (关键字段):

c
struct hrtimer {
    struct timerqueue_node  node;           // 队列节点(包含 expires)
    ktime_t                 _softexpires;   // 软到期时间
    clockid_t               clock_base->clockid; // 时钟 ID
    enum hrtimer_mode       _sexpires;     // 模式
    const void              *function;     // 回调函数
    // ... 其他字段
};

4.3 hrtimer_interrupt() 详细流程 ​

文件位置: /Users/sphinx/github/linux/kernel/time/hrtimer.c (通过 tick 调用)

核心流程在 __run_hrtimer 中实现:

c
// 伪代码表示流程
static void __run_hrtimer(struct hrtimer_cpu_base *base,
                         struct hrtimer_clock_base *clock_base,
                         struct hrtimer *timer,
                         ktime_t *now)
{
    // 1. 标记正在运行
    base->running = timer;

    // 2. 从红黑树中移除
    __remove_hrtimer(timer, clock_base, HRTIMER_STATE_INACTIVE, 0);

    // 3. 清除 ENQUEUED 状态
    timer->state &= ~HRTIMER_STATE_ENQUEUED;

    // 4. 调用回调函数
    fn = timer->function;
    restart = fn(timer);

    // 5. 处理重复定时器
    if (restart != HRTIMER_NORESTART) {
        // 重新入队
        enqueue_hrtimer(timer, clock_base, mode);
    }

    // 6. 清除运行标记
    base->running = NULL;
}

4.4 定时器迁移 (migration) ​

文件位置: /Users/sphinx/github/linux/kernel/time/hrtimer.c 第 250-297 行

c
static inline struct hrtimer_clock_base *
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
                    int pinned)
{
    struct hrtimer_cpu_base *new_cpu_base, *this_cpu_base;
    struct hrtimer_clock_base *new_base;
    int basenum = base->index;

    this_cpu_base = this_cpu_ptr(&hrtimer_bases);

    // 获取目标 CPU 基址
    new_cpu_base = get_target_base(this_cpu_base, pinned);

new_base = &new_cpu_base->clock_base[basenum];

    if (base != new_base) {
        // 检查定时器是否正在运行
        if (unlikely(hrtimer_callback_running(timer)))
            return base;  // 正在运行,不能迁移

        // 切换到迁移基址
        WRITE_ONCE(timer->base, &migration_base);
        raw_spin_unlock(&base->cpu_base->lock);
        raw_spin_lock(&new_base->cpu_base->lock);

        // 检查目标是否合适
        if (!hrtimer_suitable_target(timer, new_base, new_cpu_base,
                                     this_cpu_base)) {
            raw_spin_unlock(&new_base->cpu_base->lock);
            raw_spin_lock(&base->cpu_base->lock);
            new_cpu_base = this_cpu_base;
            WRITE_ONCE(timer->base, base);
            goto again;
        }
        WRITE_ONCE(timer->base, new_base);
    } else {
        if (!hrtimer_suitable_target(...)) {
            new_cpu_base = this_cpu_base;
            goto again;
        }
    }
    return new_base;
}

5. Posix Timer 机制 ​

5.1 struct k_itimer 完整结构 ​

文件位置: /Users/sphinx/github/linux/include/linux/posix-timers.h 第 186-223 行

c
struct k_itimer {
    /* 第一个缓存行 - 只读字段 */
    struct hlist_node       t_hash;          // 哈希表节点
    struct hlist_node       list;             // 信号定时器列表节点
    timer_t                 it_id;            // 定时器 ID
    clockid_t               it_clock;        // 时钟类型
    int                     it_sigev_notify; // 信号通知方式
    enum pid_type           it_pid_type;      // PID 类型
    struct signal_struct    *it_signal;      // 所属信号结构
    const struct k_clock    *kclock;         // 时钟处理函数集

    /* 第二个缓存行 - 频繁修改的字段 */
    spinlock_t              it_lock;         // 保护锁
    int                     it_status;        // 定时器状态
    bool                    it_sig_periodic;  // 周期信号标志
    s64                     it_overrun;       // 超限计数
    s64                     it_overrun_last;  // 上次超限计数
    unsigned int            it_signal_seq;    // 信号序列号
    unsigned int            it_sigqueue_seq;  // sigqueue 序列号
    ktime_t                 it_interval;     // 间隔时间

    struct hlist_node       ignored_list;     // 被忽略的定时器列表
    union {
        struct pid           *it_pid;         // 目标进程 PID
        struct task_struct   *it_process;     // 目标任务
    };
    struct sigqueue         sigq;             // 内嵌的 sigqueue
    rcuref_t                rcuref;          // 引用计数

    union {
        struct {
            struct hrtimer  timer;           // 实时定时器
        } real;
        struct cpu_timer      cpu;            // CPU 定时器
        struct {
            struct alarm    alarmtimer;      // 闹钟定时器
        } alarm;
    } it;

    struct rcu_head         rcu;               // RCU 头
};

定时器状态:

c
enum {
    POSIX_TIMER_DISARMED,       // 已 disarm
    POSIX_TIMER_ARMED,           // 已激活
    POSIX_TIMER_REQUEUE_PENDING, // 等待重新排队
};

5.2 ITIMER_REAL vs ITIMER_VIRTUAL vs ITIMER_PROF ​

这些通过 struct cpu_timer 实现:

c
struct cpu_timer {
    struct timerqueue_node    node;           // 定时器队列节点
    struct timerqueue_head    *head;           // 所属队列头
    struct pid                *pid;           // 目标 PID
    struct list_head          elist;          // 到期列表
    bool                      firing;         // 正在触发
    bool                      nanosleep;      // 用于 nanosleep
    struct task_struct __rcu *handling;       // 处理定时器的任务
};

ITIMER_REAL (ITIMER_REAL):

  • 使用 k_itimer.it.real.timer (hrtimer)
  • 基于 CLOCK_REALTIME
  • 到期发送 SIGALRM

ITIMER_VIRTUAL (ITIMER_VIRTUAL):

  • 使用 cpu_timer 结构
  • 基于 CLOCK_PROCESS_CPUTIME_ID
  • 只计算进程用户态时间
  • 到期发送 SIGVTALRM

ITIMER_PROF (ITIMER_PROF):

  • 使用 cpu_timer 结构
  • 基于 CLOCK_PROCESS_CPUTIME_ID
  • 计算进程用户态和内核态时间
  • 到期发送 SIGPROF

5.3 timer_create() syscall 流程 ​

文件位置: /Users/sphinx/github/linux/kernel/time/posix-timers.c 第 566-578 行

c
SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
                struct sigevent __user *, timer_event_spec,
                timer_t __user *, created_timer_id)
{
    if (timer_event_spec) {
        sigevent_t event;
        if (copy_from_user(&event, timer_event_spec, sizeof(event)))
            return -EFAULT;
        return do_timer_create(which_clock, &event, created_timer_id);
    }
    return do_timer_create(which_clock, NULL, created_timer_id);
}

do_timer_create 流程 (posix-timers.c 第 458-564 行):

c
static int do_timer_create(clockid_t which_clock, struct sigevent *event,
                           timer_t __user *created_timer_id)
{
    const struct k_clock *kc = clockid_to_kclock(which_clock);
    struct k_itimer *new_timer;
    int error, new_timer_id;

    // 1. 分配定时器结构
    new_timer = alloc_posix_timer();
    if (!new_timer)
        return -EAGAIN;

    spin_lock_init(&new_timer->it_lock);

    // 2. 添加到哈希表
    new_timer_id = posix_timer_add(new_timer, TIMER_ANY_ID);
    if (new_timer_id < 0) {
        posixtimer_free_timer(new_timer);
        return new_timer_id;
    }

    // 3. 初始化定时器字段
    new_timer->it_clock = which_clock;
    new_timer->kclock = kc;
    new_timer->it_overrun = -1LL;

    // 4. 设置信号通知
    if (event) {
        new_timer->it_pid = get_pid(good_sigevent(event));
        new_timer->it_sigev_notify = event->sigev_notify;
        // ... 设置 sigq info
    } else {
        new_timer->it_sigev_notify = SIGEV_SIGNAL;
        // ... 默认设置
    }

    // 5. 拷贝 timer_id 到用户空间
    if (copy_to_user(created_timer_id, &new_timer_id, sizeof(new_timer_id))) {
        error = -EFAULT;
        goto out;
    }

    // 6. 调用时钟特定的创建回调
    error = kc->timer_create(new_timer);
    if (error)
        goto out;

    // 7. 完成初始化,设置 it_signal
    scoped_guard (spinlock_irq, &new_timer->it_lock) {
        guard(spinlock)(&current->sighand->siglock);
        WRITE_ONCE(new_timer->it_signal, current->signal);
        hlist_add_head_rcu(&new_timer->list, &current->signal->posix_timers);
    }

    return 0;
out:
    posix_timer_unhash_and_free(new_timer);
    return error;
}

5.4 信号派发机制 ​

定时器到期处理 (posix-timers.c 第 367-374 行):

c
static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
{
    struct k_itimer *timr = container_of(timer, struct k_itimer, it.real.timer);

    guard(spinlock_irqsave)(&timr->it_lock);
    posix_timer_queue_signal(timr);
    return HRTIMER_NORESTART;
}

信号队列函数 (posix-timers.c 第 349-358 行):

c
void posix_timer_queue_signal(struct k_itimer *timr)
{
    lockdep_assert_held(&timr->it_lock);

    if (!posixtimer_valid(timr))
        return;

    timr->it_status = timr->it_interval ?
                       POSIX_TIMER_REQUEUE_PENDING : POSIX_TIMER_DISARMED;
    posixtimer_send_sigqueue(timr);
}

6. 性能优化 ​

6.1 时间戳缓存 ​

tk_fast - NMI 安全的时间读取 (timekeeping.c 第 96-107 行):

c
struct tk_fast {
    seqcount_latch_t    seq;      // 序列计数器(闩锁)
    struct tk_read_base base[2];  // 双缓冲区
};

Latch 技术 - 避免 NMI 中读取不一致:

c
static void update_fast_timekeeper(const struct tk_read_base *tkr,
                                  struct tk_fast *tkf)
{
    struct tk_read_base *base = tkf->base;

    // 强制读者使用 base[1]
    write_seqcount_latch_begin(&tkf->seq);

    // 更新 base[0]
    memcpy(base, tkr, sizeof(*base));

    // 强制读者使用 base[0]
    write_seqcount_latch(&tkf->seq);

    // 更新 base[1]
    memcpy(base + 1, base, sizeof(*base));

    write_seqcount_latch_end(&tkf->seq);
}

快速读取函数 (timekeeping.c 第 442-456 行):

c
static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
{
    struct tk_read_base *tkr;
    unsigned int seq;
    u64 now;

    do {
        seq = read_seqcount_latch(&tkf->seq);
        tkr = tkf->base + (seq & 0x01);
        now = ktime_to_ns(tkr->base);
        now += timekeeping_get_ns(tkr);
    } while (read_seqcount_latch_retry(&tkf->seq, seq));

    return now;
}

6.2 批量处理 ​

logarithmic_accumulation - 对数累积 (timekeeping.c 第 2283-2315 行):

c
static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset,
                                    u32 shift, unsigned int *clock_set)
{
    u64 interval = tk->cycle_interval << shift;
    u64 snsec_per_sec;

    if (offset < interval)
        return offset;

    // 累积一个移位间隔
    offset -= interval;
    tk->tkr_mono.cycle_last += interval;
    tk->tkr_raw.cycle_last  += interval;

    tk->tkr_mono.xtime_nsec += tk->xtime_interval << shift;
    *clock_set |= accumulate_nsecs_to_secs(tk);

    // 累积原始时间
    tk->tkr_raw.xtime_nsec += tk->raw_interval << shift;
    // ...

    return offset;
}

6.3 RCU 在 timekeeping 中的应用 ​

定时器哈希表 (posix-timers.c 第 42-55 行):

c
struct timer_hash_bucket {
    spinlock_t          lock;
    struct hlist_head   head;
};

static struct {
    struct timer_hash_bucket *buckets;
    unsigned long       mask;
    struct kmem_cache   *cache;
} __timer_data;

RCU 保护的查找 (posix-timers.c 第 89-101 行):

c
static struct k_itimer *posix_timer_by_id(timer_t id)
{
    struct signal_struct *sig = current->signal;
    struct timer_hash_bucket *bucket = hash_bucket(sig, id);
    struct k_itimer *timer;

    hlist_for_each_entry_rcu(timer, &bucket->head, t_hash) {
        if ((READ_ONCE(timer->it_signal) == sig) && (timer->it_id == id))
            return timer;
    }
    return NULL;
}

定时器释放使用 RCU (posix-timers.c 第 439 行):

c
void posixtimer_free_timer(struct k_itimer *tmr)
{
    put_pid(tmr->it_pid);
    if (tmr->sigq.ucounts)
        dec_rlimit_put_ucounts(tmr->sigq.ucounts, UCOUNT_RLIMIT_SIGPENDING);
    kfree_rcu(tmr, rcu);  // RCU 延迟释放
}

数据结构关系图 ​

+------------------+     +---------------------+
| tick_device      |     | clock_event_device  |
+------------------+     +---------------------+
| evtdev    -------+---->| event_handler       |
| mode            |     | set_next_event      |
+------------------+     | next_event         |
                         | mult/shift         |
                         | features           |
                         +---------------------+
                                ^
                                |
                    tick_check_new_device()
                                |
                         +---------------------+
                         | tick_sched          |
                         +---------------------+
                         | sched_timer (hrtimer)
                         | flags               |
                         | idle_jiffies       |
                         +---------------------+
                                ^
                                |
                    tick_nohz_next_event()
                                |
                         +---------------------+
                         | timekeeper          |
                         +---------------------+
                         | tkr_mono           |
                         | xtime_sec          |
                         | wall_to_monotonic  |
                         | offs_real/boot/tai|
                         | ntp_tick           |
                         +---------------------+
                                ^
                                |
                         update_wall_time()
                                |
                         +---------------------+
                         | clocksource         |
                         +---------------------+

关键算法流程图 ​

tick 周期处理流程 ​

tick_handle_periodic()
        |
        v
tick_periodic(cpu)
        |
        +-- do_timer(1)  ---> update_wall_time()
        |                       |
        |                       v
        |                 __timekeeping_advance()
        |                       |
        |                       v
        |                 logarithmic_accumulation()
        |                       |
        |                       v
        |                 timekeeping_adjust()
        |                       |
        |                       v
        |                 accumulate_nsecs_to_secs()
        |
        +-- update_process_times()
        |         |
        |         v
        +-- profile_tick()

hrtimer 中断处理流程 ​

hrtimer_interrupt()
        |
        v
__run_hrtimer()
        |
        +-- 1. __remove_hrtimer() - 从红黑树移除
        |
        +-- 2. 调用回调函数 fn(timer)
        |
        +-- 3. 如果返回 HRTIMER_RESTART,重新入队
        |
        v
hrtimer_force_reprogram()
        |
        v
__hrtimer_reprogram()
        |
        v
tick_program_event()

参考文件列表 ​

文件描述
kernel/time/tick-common.cTick 设备基础管理
kernel/time/tick-sched.cNO_HZ 和动态 tick 实现
kernel/time/tick-sched.htick_sched 结构定义
kernel/time/clockevents.cClockevent 设备管理
kernel/time/timekeeping.cTimekeeping 核心实现
kernel/time/timekeeping.htimekeeping 内部接口
include/linux/timekeeper_internal.htimekeeper 结构定义
kernel/time/hrtimer.cHrtimer 实现
include/linux/hrtimer_defs.hhrtimer 核心结构定义
kernel/time/posix-timers.cPOSIX 定时器实现
include/linux/posix-timers.hk_itimer 结构定义
include/linux/clockchips.hclock_event_device 定义

文档版本: R1生成日期: 2026-04-26

基于 VitePress 构建