一文了解通透通用时间子系统

本文深入介绍了Linux内核的timekeeping模块,包括其核心数据结构struct timekeeper,初始化过程,获取和设置系统时钟的方法,以及与clocksource和tick模块的交互。timekeeping模块维护了多种系统时钟,如real time、monotonic和boot time clock,并通过clocksource获取精确时间信息。
摘要由CSDN通过智能技术生成

一、前言

timekeeping模块是一个提供时间服务的基础模块。Linux内核提供各种time line,real time clock,monotonic clock、monotonic raw clock等,timekeeping模块就是负责跟踪、维护这些timeline的,并且向其他模块(timer相关模块、用户空间的时间服务等)提供服务,而timekeeping模块维护timeline的基础是基于clocksource模块和tick模块。通过tick模块的tick事件,可以周期性的更新time line,通过clocksource模块、可以获取tick之间更精准的时间信息。

本文熟悉介绍timekeeping的一些基础概念,接着会介绍该模块初始化的过程,此后会从上至下介绍该模块提供的服务、该模块如何和tick模块交互以及如何和clocksource模块交互,最后介绍电源管理相关的内容。

二、timekeeper核心数据定义

1、struct timekeeper数据结构解析

旧的内核定义了很多零散的全局变量来管理linux kernel中的各种系统clock,现在,内核定义的struct timekeeper数据结构来管理各种系统时钟的跟踪以及控制,定义如下:

struct timekeeper { 
    struct clocksource    *clock;------------------------(1) 
 
    u32            mult;-----------------------------(2) 
    u32            shift;

    cycle_t            cycle_interval; -----------------------(3) 
    cycle_t            cycle_last; 
    u64            xtime_interval; 
    s64            xtime_remainder; 
    u32            raw_interval;
    s64            ntp_error; 
    u32            ntp_error_shift;
 
    u64            xtime_sec;---------------------------(4) 
    u64            xtime_nsec;
 
    struct timespec        wall_to_monotonic; -------------------(5) 
    ktime_t            offs_real;      
    struct timespec        total_sleep_time; ------记录系统睡眠时间 
    ktime_t            offs_boot; ------------记录系统boot time 
 
    struct timespec        raw_time; -----------------------(6) 
 
    s32            tai_offset; ---------------------------(7) 
    ktime_t            offs_tai;
};

(1)timekeeper当前使用的clocksource。这个clock应该系统中最优的那个,如果有好过当前clocksource注册入系统,那么clocksource模块会通知timekeeping模块来切换clocksource。

(2)clock source的cycle值和纳秒转换的facotr,概念和clocksource的mult和shift一致。

(3)NTP相关的成员,这里不详述了,实在是对NTP没有兴趣。

(4)CLOCK_REALTIME类型的系统时钟(其实就是墙上时钟)。我们都知道,时间就像是一条直线(line),不知道起点,也不知道终点,因此我们称之time line。time line有很多种,和如何定义0值的时间以及用什么样的刻度来度量时间相关。人类熟悉的墙上时间和linux kernel中定义的CLOCK_REALTIME都是用来描述time line的,只不过时间原点和如何度量time line上两点距离的刻度不一样。对于人类的时间,0值是耶稣诞生的时间点;对于CLOCK_REALTIME,0值是linux epoch,即1970年1月1日...。对于墙上时间,在度量的时候虽然也是基于秒的,但是人类做了grouping,因此使用了年月日时分秒的概念。这里的秒数是相对与当前分钟值内的秒数。对于linux世界中的CLOCK_REALTIME time,直接使用秒以及纳秒在当前秒内的偏移来表示。
因此,这里xtime_sec用秒这个的刻度单位来度量CLOCK_REALTIME time line上,时间原点到当前点的距离值。当然xtime_sec是一个对current time point的取整值,为了更好的精度,还需要一个纳秒表示的offset,也就是xtime_nsec。
不过为了内核内部计算精度(内核对时间的计算是基于cycle的),并不是保存了时间的纳秒偏移值,而是保存了一个shift之后的值,因此,用户看来,当前时间点的值应该是距离时间原点xtime_sec + (xtime_nsec << shift)距离的那个时间点值

(5)CLOCK_MONOTONIC类型的系统时钟。这种系统时钟并没有象墙上时钟一样定义一个相对于linux epoch的值,这个成员定义了monotonic clock到real time clock的偏移,也就是说,这里的wall_to_monotonic和offs_real需要加上real time clock的时间值才能得到monotonic clock的时间值。当然,从这里成员的名字就看出来了。wall_to_monotonic和offs_real的意思是一样的,不过时间的格式不一样,用在不同的场合,以便获取性能的提升。

(6)CLOCK_MONOTONIC_RAW类型的系统时钟

(7)CLOCK_TAI类型的系统时钟。TAI(international atomic time)是原子钟,在时间的基本概念文档中,我们说过,UTC就是base TAI的,也就是说用铯133的振荡频率来定义秒的那个时钟,当然UTC还有考虑leap second以便方便广大人民群众。CLOCK_TAI类型的系统时钟就是完完全全使用铯133的振荡频率来定义秒的那个时钟,不向人类妥协。

2、全局变量

static struct timekeeper timekeeper; 
static DEFINE_RAW_SPINLOCK(timekeeper_lock); 
static seqcount_t timekeeper_seq;
static struct timekeeper shadow_timekeeper;

timekeeper维护了系统的所有的clock。一个全局变量(共享资源)没有锁保护怎么行,timekeeper_lock和timekeeper_seq都是用来保护timekeeper的,用在不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值