概述
目录
- 概述
- 非标准PC的硬件时钟初始化
- 认识jiffies
- clocksource框架
- 如何获取时间
- clocksource结构体
- clocksource注册的实现
最近学习RTC,了解下Linux kernel的计时器和时间管理机制,通过LINUX INSIDES
阅读笔记1是前两个章节的内容
概述
非标准PC的硬件时钟初始化
1.intel MID
x86_init.timers.wallclock_init = intel_mid_rtc_init;
初始化set_time 和 get_time 函数
2.标准设备
.wallclock_init = x86_init_noop,
调用x86_init_noop时啥也不做
认识jiffies
linuxkernel的全局变量jiffies记录了自系统启动以来所有的节拍数(节拍:两个时钟中断的间隔时间)
register_refined_jiffies
不是硬件相关的函数,这是jiffy的clocksource
的注册
在/kernel/time/jiffies.c有两个结构体
struct clocksource clocksource_jiffies
与时钟中断频率相同,有点不够精确
struct clocksource refined_jiffies;
用CLOCK_TICK_RATE
作为shift
注册要用/include/linux/clocksource.h提供的API__clocksource_register
用jiffies来衡量时间
/* 30s 之后 */
jiffies + 30*HZ
/* 2min 之后 */
jiffies + 120*HZ
/* 1ms 之后 */
jiffies + HZ / 1000
jiffies / HZ
是系统开机以来的秒数总和
clocksource框架
clocksource
是一个计时抽象,为系统提供时间。
结构体定义在include/linux/clocksource.h
这么做的原因?不同的硬件时钟提供不同的资源,一些更加准确的时间测量方法视设备而定。因此需要有进一步的抽象和相关的API来管理时钟资源并且可以独立于时钟中断,因此有了clocksource框架
这么做的目的?支持用户在不同的支持时钟功能的设备中做出选择
如何获取时间
- RTC设备
drivers/rtc下的一系列RTC && 不同计算机架构的RTC,如X86下的CMOS/RTC - 系统计时器
clocksource结构体
struct clocksource {
u64 (*read)(struct clocksource *cs); //返回clocksource框架选择的最好计数器
u64 mask; //非64位计数器的计数值减法不需要额外的溢出逻辑
u32 mult;
u32 shift; //mult和shift方便将机器时间转换为纳秒
u64 max_idle_ns; //最大空闲时间,开启`CONFIG_NO_HZ`的linux kernel需要有变量约束休眠时间
u32 maxadj; //mult的最大调整值
u32 uncertainty_margin;
#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA //配置相关
struct arch_clocksource_data archdata;
#endif
u64 max_cycles; //可能的溢出前的最大cycle value
const char *name; //名字
struct list_head list;
int rating; //选时钟资源的
enum clocksource_ids id;
enum vdso_clock_mode vdso_clock_mode;
unsigned long flags;
int (*enable)(struct clocksource *cs);//开启
void (*disable)(struct clocksource *cs);//关闭
void (*suspend)(struct clocksource *cs);//暂停
void (*resume)(struct clocksource *cs);//中断后恢复
void (*mark_unstable)(struct clocksource *cs);
void (*tick_stable)(struct clocksource *cs);
/* private: */
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG //配置相关
/* Watchdog related data, used by the framework */
struct list_head wd_list;
u64 cs_last;
u64 wd_last;
#endif
struct module *owner; //内核module是clocksource的所有者
};
clocksource注册的实现
前边提到的__clocksource_register
,clocksource_register_hz
和clocksource_register_khz
其具体实现都用到了一个__clocksource_register_scale(cs,scale,freq)
- cs 要被安装的时钟源
- scale 比例因子
- freq 时钟源频率
int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
{
__clocksource_update_freq_scale(cs, scale, freq); //更新时钟源
mutex_lock(&clocksource_mutex); //获取互斥锁
clocksource_enqueue(cs); //遍历clocksource_list,并给出放置时钟源的位置
clocksource_enqueue_watchdog(cs);
clocksource_select(); //从所有注册的时钟源中选出一个
mutex_unlock(&clocksource_mutex);
return 0;
}
__clocksource_update_freq_scale的函数最后会将结果打印到内核缓冲区,可通过dmesg | grep "clocksource:"
查看
pr_info("%s: mask: 0x%llx max_cycles: 0x%llx, max_idle_ns: %lld nsn",
cs->name, cs->mask, cs->max_cycles, cs->max_idle_ns);
[root@localhost dev]# dmesg | grep "clocksource:"
[ 0.075784] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1910969940391419 ns
[ 0.407563] clocksource: hpet: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 133484882848 ns
[ 0.408524] clocksource: tsc-early: mask: 0xffffffffffffffff max_cycles: 0x255cb7d21a7, max_idle_ns: 440795311043 ns
[ 0.475495] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275000 ns
[ 0.706655] clocksource: Switched to clocksource tsc-early
[ 0.780600] clocksource: acpi_pm: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 2085701024 ns
[ 2.808292] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x255cb206edb, max_idle_ns: 440795262788 ns
选出最佳时钟源之后,也会打印到开机信息
pr_info(“Switched to clocksource %sn”, best->name);
[root@localhost dev]# dmesg | grep Switched
[ 0.706655] clocksource: Switched to clocksource tsc-early
[ 2.808655] clocksource: Switched to clocksource tsc
除此以外,clocksource框架还用init_clocksource_sysfs
函数给出了sysfs
改函数主要创建了三个文件dev_attr_current_clocksource
/ dev_attr_unbind_clocksource
/dev_attr_available_clocksource
这样就可以通过命令行来查看一些信息了
[root@localhost dev]# cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm
[root@localhost dev]# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
最后
以上就是开放冰棍为你收集整理的Linux Inside的计时器和时间管理章节阅读笔记1概述clocksource框架的全部内容,希望文章能够帮你解决Linux Inside的计时器和时间管理章节阅读笔记1概述clocksource框架所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复