簡單介紹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字段對應的節點處理便可。