linux硬时钟,TSC,PIT, RTC
RTC:实时时钟,即保存当前时间。
PIT:硬件可编程间隔定时器,每一个(可编程的)间隔后发出一个时钟中断
TSC:每个时钟中断时,都会自动加一。
频率与时钟是不同的。
CLOCK_RATE是晶振频率,送入芯片中。
LATCH:即PIT中的间隔,可编程,当LATCH递减为0时,产生一个时钟中断,然后重置为LATCH初值。
HZ:时钟频率,即一秒内发生多少个时钟中断。
硬件时钟:
主要结构: clocksource, 描述一个硬件时钟源的信息。
clock_event_device, 描述一个时钟中断后执行的行为。 时钟事件设备
linux内核中主要使用两个全局链表来存所有的硬时钟信息。
clocksource_list
clockevent_devices
通知链技术(观察者模式): notification chain
有四种链,用于不同的场合。原子,可阻塞,原始通知,SRCU
主要结构:
struct notifier_block, 通知链中元素的结构。
动作机制:
被通知者要把自己的函数加进通知链中,然后当通知者的事件产生,则会遍历链上元素,调用上面的每一个函数。
linux中硬件时钟中断的初始化。
中断的处理函数在irq0。
static struct irqaction irq0 = {
.handler = timer_event_interrupt,
.flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
.mask = CPU_MASK_NONE,
.name = "timer"
};
内核初始化部分( start_kernel 函数)和时钟相关的过程主要有以下几个:
tick_init() // 向全局clockevents_chain通知链中添加一个 tick_notifier函数,当时钟事件设备信息变化,就会执行这个clockevents_chain中所有回调函数。
init_timers() // 初始化 时钟的软中断处理函数。 时钟softirq?
hrtimers_init() //PIT HRPIT,初始化PIT,及硬中断产生时的中断处理函数(IRQ0)
其中函数 hrtimers_init() 和高精度时钟相关
time_init() // 初始化TSC时钟源。
硬件中断处理过程:(每次硬件中断处理完后,就会调用调用软中断)
每次硬中断产生后会调用中断处理: timer_event_interrupt,其实际上调用的是 global_clock_event 变量的 event_handler 成员,而event_handler是在向内核添加PIT硬时钟设备时,调用用tick_check_new_device 。tick_set_periodic_handler 函数将时钟事件设备的 event_handler 成员赋值为 tck_handle_periodic 函数的地址,
即硬中断产生后,真正调用的函数是:tick_handle_periodic函数:
全局处理:
更新jiffies
更新xtime与当前时钟源信息
根据tick计算avenrun负载
局部(单个CPU)处理:
统计当前进程CPU时间(用户时间/内核时间)
唤醒时间软中断, //软件定时器处理。
唤醒RCU软中断,
更新进程时间片 scheduler_tick
profile_tick.
软件定时器:
主要结构:
struct time_list, 软件定时器结构
struct tvec_base,用于组织软件定时器。
struct tvec, 软件定时器向量, 实际上就是一个list_head数组。每个数组成员是一段时间内到期的所有定时器的链表头。
每个CPU都有自己的一个组织时钟结构: tvec_base
里面有5个时钟向量tvec,用于存放不同到期时间的软件定时器。
linux内核的组织方式是:
每个CPU一个tvec_base
每个tvec_base中有5个tvec
[256] 0 - 2^8 -1
[64] 2^8 - 2^14 -1
[64] 2^14 - 2^20 -1
[64] 2^20 - 2^26 -1
[64] 2^26 - 00
软件定时器的处理:
软中断的一个重要的处理时机是在每个硬件中断处理完成后(参见 irq_exit 函数),而软件定时器的处理是在软中断上下文中实现的。
先是得到tvec_base,然后执行所有的到期的定时器,然后调整定时器向量。cascade 函数
应用:进程定时睡眼。