【Linux内核|时间子系统】Linux时间子系统(一)简介

1. 简介

内核版本:linux-6.1

时间子系统的作用:

  1. 时间读取功能
  2. 定时器功能,有传统的定时器timer、高精度定时器hrtimer
  3. 提供用于调度的tick,有周期tick和动态tick

2. Linux的各种时间

Linux的系统时钟ID定义如下,选其中常用的简单介绍一下。

相关的文档可以查看内核文档Documentation/core-api/timekeeping.rstktime accessors — The Linux Kernel documentation

用户态的clock_gettime相关接口也有一些介绍,Linux系统上,可以用man 2 clock_gettime查看,或者查看网页版clock_getres(2) - Linux manual page

wowotech介绍:Linux的时钟

/*
 * The IDs of the various system clocks (for POSIX.1b interval timers):
 */
#define CLOCK_REALTIME            0
#define CLOCK_MONOTONIC            1
#define CLOCK_PROCESS_CPUTIME_ID    2
#define CLOCK_THREAD_CPUTIME_ID        3
#define CLOCK_MONOTONIC_RAW        4
#define CLOCK_REALTIME_COARSE        5
#define CLOCK_MONOTONIC_COARSE        6
#define CLOCK_BOOTTIME            7
#define CLOCK_REALTIME_ALARM        8
#define CLOCK_BOOTTIME_ALARM        9

2.1. 墙上时间(REALTIME)

真实时间的时间,也就是协调世界时(UTC) ,起始于1970年1月1日0时0分0秒。

在内核中,REALTIME用在需要在重启期间保持的时间戳,如文件inode时间。这个时间会受到系统时间不连续跳跃的影响,比如闰秒更新、NTP调整settimeofday操作,应尽量避免用于内部使用。

2.2. 单调时间(MONOTONIC)

不可设置的全系统时钟,表示单调时间,正如POSIX所描述的那样——“过去某个未指定的点”。在Linux上,该点对应于系统自启动以来运行的秒数。CLOCK_MONOTONIC时钟不受系统时间不连续跳跃的影响(例如,如果系统管理员手动更改时钟),但受adjtime和NTP执行的增量调整的影响。此时钟不计算系统暂停的时间。在内核中用于可靠的时间戳和精确测量短时间间隔。用户态所有CLOCK_MONOTONIC变体都保证连续调用返回的时间不会倒退,但连续调用可能会根据体系结构返回相同(而不是增加)的时间值。

2.3. 单调时间(MONOTONIC_RAW)

与MONOTONIC类似,是基于硬件的原始时间,不受adjtime或NTP(Network Time Protocol,网络时间协议)调整的影响。在内核中也很少用到。

2.4. 系统启动时间(BOOTTIME)

不可设置的全系统时钟,与MONOTONIC类似,但它会统计系统挂起的时间。会受到settimeofday获取其他相关系统调用影响。

内核中可以用在需要系统挂起之后与其他机器保持时间同步的场景,比如密钥过期时间。

2.5. 国际原子时(TAI)

TAI是International Atomic Time的反向简称。一种不可设置的全系统时钟,源自墙上时间,忽略闰秒问题,不会有REALTIME由NTP插入闰秒引起的中断和向后跳转。内核中很少用到。

3. 时间子系统的初始化

时间子系统初始化中调用关系如下,其中timekeeping_init和time_init是比较重要的函数。后边会在做介绍。

在这里插入图片描述

3.1. tick_init

broadcast和nohz初始化,这里都是针对子系统软件上的初始化,没有实际的硬件操作。

broadcast用来实现CPU suspend后的唤醒等,nohz则与动态时钟调度相关。

tick_broadcast_init主要是一些CPU mask标志的初始化。

tick_nohz_init也依赖tick_nohz_full_running,如果tick_nohz_full_running为false,就直接返回了。而tick_nohz_full_running只有在housekeeping_setup -> tick_nohz_full_setup才会被设为true,需要使能CONFIG_CPU_ISOLATION才有可能被调到。

/**
 * tick_init - initialize the tick control
 */
void __init tick_init(void)
{
    tick_broadcast_init();
    tick_nohz_init();
}

3.2. init_timers

init_timers是针对传统定时器的初始化,主要完成两个工作:

  1. percpu变量timer_bases。

  2. 打开TIMER_SOFTIRQ软中断

void __init init_timers(void)
{
    init_timer_cpus();
    posix_cputimers_init_work();
    open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}

3.3. hrtimers_init

hrtimer顾名思义就是高精度定时器,hrtimers_init主要完成两个工作:

  1. 初始struct hrtimer_cpu_base,percpu变量hrtimer_bases。

  2. 打开HRTIMER_SOFTIRQ软中断

void __init hrtimers_init(void)
{
    hrtimers_prepare_cpu(smp_processor_id());
    open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq);
}

3.4. timekeeping_init

timekeeping_init是时间子系统非常重要的一个初始化,实现了各种时间基准的初始化,tk_core的timekeeper是timekeeping核心,并由tk_core衍生出了tk_fast_mono和tk_fast_raw,ktime_get相关的接口都是基于tk_core.timekeeper或tk_fast_mono、tk_fast_raw来获取时间的。

3.5. time_init

time_init是一个体系结构相关的函数,arm64的代码位于arch/arm64/kernel/time.c,主要流程如下。

  1. of_clk_init初始化时钟
  2. timer_probe查找系统定时器并初始化
  3. tick_setup_hrtimer_broadcast,在使能高精度timer和broadcast的情况下有用,创建一个名为bctimer的hrtimer,并注册ce_broadcast_hrtimer作为clock_event_device。
  4. arch_timer_get_rate,获取arch timer的速率,如果为0,直接panic。正常情况下,在timer_probe初始化定时器后,会返回系统定时器速率。
  5. 直接用获取的arch_timer速率计算lpj_fine,lpj_fine = arch_timer_rate / HZ。作为loops_per_jiffy的一种快速获取方法,从而节省启动时间。

3.5.1. timer_probe

这里比较重要的是timer_probe,arm和arm64都要求必须要有arch_timer用来做为clocksource,提供tick来驱动系统调度。这些timer用TIMER_OF_DECLARE来声明,TIMER_OF_DECLARE用于声明一个struct of_device_id,并放到__timer_of_table段,其中struct of_device_id的data成员指向初始化换函数。比如drivers/clockcource/arm_arch_timer.c

TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
TIMER_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);

在内核启动过程中,timer_probe遍历__timer_of_table段,扫描设备树中可以匹配的定时器节点,并调用对应的初始化函数。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值