您的位置:首页 > 运维架构 > Linux

Linux时间管理 (二)

2012-08-13 18:44 288 查看

1.1     
Wheel时钟的实现(低精度定时器的实现)

通常OS操作系统都支持Wheel方式,例如Linux、Neclues和vxworks都支持100-200Hz的节拍时钟。通过节拍OS进行时钟刷新以及产生任务调度,而每个硬件节拍就称为tick

1.1.1        核心数据结构

在Linux 2.6.16之前,内核一直使用一种称为timer wheel(定时器轮)的机制来管理时钟。这就是kernel一直采用的基于HZ的timer机制。Timer
wheel 的核心数据结构如下所示:

#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)

 #define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)

 #define TVN_SIZE (1 << TVN_BITS)

 #define TVR_SIZE (1 << TVR_BITS)

 #define TVN_MASK (TVN_SIZE - 1)

 #define TVR_MASK (TVR_SIZE - 1)

 

 struct
tvec {

        struct list_head vec[TVN_SIZE];

 };

 struct
tvec_root {

        struct list_head vec[TVR_SIZE];

 };

 

 struct tvec_base {

        spinlock_t lock;

        struct timer_list *running_timer;

        unsigned long timer_jiffies;

        unsigned long next_timer;

        struct tvec_root tv1; //每一项称为一组

        struct tvec tv2;

        struct tvec tv3;

        struct tvec tv4;

        struct tvec tv5;

 } ____cacheline_aligned;

 

在SMP系统中,通过如下方式定义per-cpu变量:

struct tvec_base boot_tvec_bases;

EXPORT_SYMBOL(boot_tvec_bases);

static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;

在内存较小的系统中可以设置CONFIG_BASE_SMALL选项为1来减少内存的使用。

1.1.2       定时器到期处理

对所有定时器的处理都由update_process_times发起,具体的调用流程如下:

update_process_times

    run_local_timers

        hrtimer_run_queues

       
raise_softirq(TIMER_SOFTIRQ)

在init_timers初始化时设置TIMER_SOFTIRQ的软中处理函数为run_timer_softirq,那么在run_timer_softirq将完成对到期的定时器实际的处理工作。其调用流程如下:

run_timer_softirq

    __run_timers

 

一个弊端就是cascade开销过大。在极端的条件下,同时会有多个TV需要进行cascade处理,会产生很大的时延。这也是为什么说timeout类型的定时器是timer wheel的主要应用环境,或者说timer wheel是为timeout类型的定时器优化的。因为timeout类型的定时器的应用场景多是错误条件的检测,这类错误发生的机率很小,通常不到超时就被删除了,因此不会产生 cascade的开销。另一方面,由于timer
wheel是建立在 HZ
的基础上的,因此其计时精度无法进一步提高。毕竟一味的通过提高 HZ
值来提高计时精度并无意义,结果只能是产生大量的定时中断,增加额外的系统开销
。因此,有必要将高精度的 timer 与低精度的 timer 分开,这样既可以确保低精度的 timeout 类型的定时器应用,也便于高精度的 timer 类型定时器的应用。还有一个重要的因素是 timer wheel 的实现与 jiffies 的耦合性太强,非常不便于扩展。因此,自从2.6.16开始, hrtimer这个新的timer子系统被加入到内核中。

 

1.2   
Linux Wheel时钟的初始化过程

在kernel启动的时候完成对Linux Wheel的核心数据结构的初始化工作。具体的初始化流程为

start_kernel

       init_timers

              timer_cpu_notify

             
       init_timers_cpu

              init_timer_stats

              register_cpu_notifier

open_softirq

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息