早期的内核版本中,进程的调度基于一个称之为tick的时钟滴答,通常使用时钟中断来定时地产生tick信号,每次tick定时中断都会进行进程的统计和调度,并对tick进行计数,记录在一个jiffies变量中,定时器的设计也是基于jiffies。这时候的内核代码中,几乎所有关于时钟的操作都是在machine级的代码中实现,很多公共的代码要在每个平台上重复实现。随后,随着通用时钟框架的引入,内核需要支持高精度的定时器,为此,通用时间框架为定时器硬件定义了一个标准的接口:clock_event_device,machine级的代码只要按这个标准接口实现相应的硬件控制功能,剩下的与平台无关的特性则统一由通用时间框架层来实现。
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_t next_event;
u64 max_delta_ns;
u64 min_delta_ns;
u32 mult;
u32 shift;
enum clock_event_mode mode;
unsigned int features;
unsigned long retries;
void (*broadcast)(const struct cpumask *mask);
void (*set_mode)(enum clock_event_mode mode,
struct clock_event_device *);
unsigned long min_delta_ticks;
unsigned long max_delta_ticks;
const char *name;
int rating;
int irq;
const struct cpumask *cpumask;
struct list_head list; } ____cacheline_aligned;
event_handler 该字段是一个回调函数指针,通常由通用框架层设置,在时间中断到来时,machine底层的的中断服务程序会调用该回调,框架层利用该回调实现对时钟事件的处理。
set_next_event 设置下一次时间触发的时间,使用类似于clocksource的cycle计数值(离现在的cycle差值)作为参数。
set_next_ktime 设置下一次时间触发的时间,直接使用ktime时间作为参数。
max_delta_ns 可设置的最大时间差,单位是纳秒。
min_delta_ns 可设置的最小时间差,单位是纳秒。
mult shift 与clocksource中的类似,只不过是用于把纳秒转换为cycle。
mode 该时钟事件设备的工作模式,两种主要的工作模式分别是:
CLOCK_EVT_MODE_PERIODIC 周期触发模式,设置后按给定的周期不停地触发事件;
CLOCK_EVT_MODE_ONESHOT 单次触发模式,只在设置好的触发时刻触发一次;
set_mode 函数指针,用于设置时钟事件设备的工作模式。
rating 表示该设备的精度等级。
list 系统中注册的时钟事件设备用该字段挂在全局链表变量clockevent_devices上。