简单介绍linux下的时间子系统。包括clocksource,timekeeper和定时器的内容。node
随着内核的不断升级和硬件的不断发展,因为低精度定时器有必定的局限性,内核从2.6.16开始加入了高精度定时器架构。在实现方式上,高精度定时器的实现代码几乎没有借用低精度定时器的数据结构和代码,缘由有如下几点:linux
1 低精度定时器的代码和jiffies的关系太过紧密,而且默认按照32为进行设计,若是要基于它来实现高精度时钟,必然会打破原有的time wheel的概念,并且会引入大量的#if #else判断。数组
2 虽然大部分时间里,time wheel能够实现O(1)的时间复杂度,可是若是有进位发生,不可预测的O(n)定时器级联迁移,大大的影响了高精度定时器的精度。数据结构
3 低精度定时器几乎为超时而设计,为此对它进行了大量的优化,精确时间并非它的主要目的。架构
为此,内核为高精度定时器从新设计了一套软件架构,他能够为咱们提供纳秒级的定时精度,以知足对精确时间有迫切需求的应用和内核驱动,如多媒体应用,音频设备的驱动程序等等。函数
低精度定时器使用5个链表数组来组织timer_list结构,造成了著名的时间轮的概念。而高精度时钟,为了具有稳定而快速的查找、快速的插入和删除定时器的能力以及排序功能,内核的开发者最后选定红黑树,来组织hrtimer。随着系统的运行,hrtimer不断的被建立和销毁,新的hrtimer按照到期时间被插入到红黑树中,红黑树的最左下节点即为最快到期的定时器。内核使用hrtimer结构表示一个高精度定时器。优化
struct hrtimer {spa
struct timerqueue_node node;设计
ktime_t _softexpires;rest
enum hrtimer_restart (*function)(struct hrtimer *);
struct hrtimer_clock_base *base;
unsigned long state;
struct list_head cb_entry;
int irqsafe;
#ifdef CONFIG_TIMER_STATS
int start_pid;
void *start_site;
char start_comm[16];
#endif
};
_softexpires,表示到期时间。
function,定时器到期时的回调函数。其返回值是一个枚举值,决定了该定时器是否须要被从新激活。若是返回值为HRTIMER_RESTART,代表须要从新激活。若是为HRTIMER_NORESTART,代表不须要从新激活。
state,用于表示hrtimer当前的状态。
#define HRTIMER_STATE_INACTIVE 0x00 //定时器未激活
#define HRTIMER_STATE_ENQUEUED 0x01 // 定时器已经排入红黑树中
#define HRTIMER_STATE_CALLBACK 0x02 // 定时器的回调函数正在被调用
#define HRTIMER_STATE_MIGRATE 0x04 // 定时器正在cpu间作迁移
base,表示当前定时器是基于哪种时间基准的。hrtimer到期时间能够基于如下几种时间基准
enum hrtimer_base_type {
HRTIMER_BASE_MONOTONIC, //monotonic time
HRTIMER_BASE_REALTIME, //wall time
HRTIMER_BASE_BOOTTIME, //boot time
HRTIMER_MAX_CLOCK_BASES,
};
与低精度时钟同样,处于效率和互斥的考虑,每一个cpu单独管理属于本身的hrtimer。为此,专门定义了一个结构hrtimer_cpu_base:
struct hrtimer_cpu_base {
raw_spinlock_t lock;
unsigned long active_bases;
#ifdef CONFIG_HIGH_RES_TIMERS
ktime_t expires_next; //三种时间基准的定时器最早到期定时器的时间
int hres_active;
int hang_detected;
unsigned long nr_events;
unsigned long nr_retries;
unsigned long nr_hangs;
ktime_t max_hang_time;
#endif
#ifdef CONFIG_PREEMPT_RT_BASE
wait_queue_head_t wait;
#endif
struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; //每一个cpu都有三种时间基准的高精度定时器列表
};
struct hrtimer_clock_base {
struct hrtimer_cpu_base *cpu_base; //指向所属cpu的hrtimer_cpu_base结构
int index;
clockid_t clockid; //肯定基于哪一种时间基准
struct timerqueue_head active; //红黑树,含定时器列表
struct list_head expired;
ktime_t resolution;
ktime_t (*get_time)(void);
ktime_t softirq_time;
ktime_t offset;
};
struct timerqueue_node {
struct rb_node node;
ktime_t expires;
};
struct timerqueue_head {
struct rb_root head;
struct timerqueue_node *next;
};
timequeue_head结构在红黑树的基础上,增长了一个next字段,用于保存红黑树中最早到期的定时器节点,实际上就是红黑树的最左下节点。有了next字段,系统就没必要遍历整个红黑树,只要取出next字段对应的节点处理便可。