Ubuntu Kylin技术论坛

 找回密码
查看: 2538|回复: 0

linux时间子系统(六)

[复制链接]
  • TA的每日心情
    奋斗
    2018-4-21 12:43
  • 签到天数: 63 天

    [LV.6]常住居民II

    发表于 2018-5-28 17:18:32 | 显示全部楼层 |阅读模式
    3.1.4 定时器处理
    static inline void __run_timers(struct tvec_base *base)
    {
            struct timer_list *timer;
            spin_lock_irq(&base->lock);
            while (time_after_eq(jiffies, base->timer_jiffies)) {
                    struct list_head work_list;
                    struct list_head *head = &work_list;
                    int index = base->timer_jiffies & TVR_MASK;
                    /*
                     * Cascade timers:
                     */
                    if (!index &&
                            (!cascade(base, &base->tv2, INDEX(0))) &&
                                    (!cascade(base, &base->tv3, INDEX(1))) &&
                                            !cascade(base, &base->tv4, INDEX(2)))
                            cascade(base, &base->tv5, INDEX(3));
                    ++base->timer_jiffies;
                    list_replace_init(base->tv1.vec + index, &work_list);
                    while (!list_empty(head)) {
                            void (*fn)(unsigned long);
                            unsigned long data;
                            timer = list_first_entry(head, struct timer_list,entry);
                            fn = timer->function;
                            data = timer->data;
                            timer_stats_account_timer(timer);
                            base->running_timer = timer;
                            detach_timer(timer, 1);
                            spin_unlock_irq(&base->lock);
                            call_timer_fn(timer, fn, data);
                            base->running_timer = NULL;
                            spin_lock_irq(&base->lock);
                    }
            }
            wake_up(&base->wait_for_running_timer);
            spin_unlock_irq(&base->lock);
    }
    static int cascade(struct tvec_base *base, struct tvec *tv, int index)
    {
            /* cascade all the timers from tv up one level */
            struct timer_list *timer, *tmp;
            struct list_head tv_list;
            list_replace_init(tv->vec + index, &tv_list);
            /*              
             * We are removing _all_ timers from the list, so we
             * don't have to detach them individually.
             */            
            list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
                    BUG_ON(tbase_get_base(timer->base) != base);
                    internal_add_timer(base, timer);
            }      
            
            return index;
    }
       当前cpu的tvec_base.timer_jiffies的低8位不为0时,按tv1-tv5组成的32位数做加法运算来看,tv1到tv2没有发生进位,所以可以直接处理tvec_base.timer_jiffies的低8位作为下标索引的tv1中的定时器链表中的定时器即可。此时调用定时器的回调函数处理即可。而当tvec_base.timer_jiffies的低8位为0时,表明发生了进位,此时需要从高一级别的tv2中取出((base->timer_jiffies >> (TVR_BITS + (0) * TVN_BITS)) & TVN_MASK)作为索引下标的链表,使用函数internal_add_timer将链表中的数组逐一添加到tv1中。当低14位全为0时,表明tv1向tv2进位,tv2向tv3进位,此时,先完成tv2向tv1的迁移,在完成tv3到tv2的迁移。后续过程依次类推。
    3.1.5 定时器的使用
      在使用定时器之前,我们需要知道如何定义定时器。在内核编程中使用定时器,首先我们需要定义一个time_list结构
    3.1.5.1 timer_list结构
    struct timer_list {
            /*
             * All fields that change during normal runtime grouped to the
             * same cacheline
             */     
            struct list_head entry;
            unsigned long expires;
            struct tvec_base *base;
                
            void (*function)(unsigned long);
            unsigned long data;
             
            int slack;
    .....
    }
    entry,用于把一组定时器组成一个链表。
    expires,定时器的到期时刻。也就是定时器到期时刻的jiffies计数值。
    base,每个cpu拥有一个自己的用于管理定时器的tvec_base结构。该字段指向定时器所属cpu所对应的tvec_base结构。
    function,函数指针。定时器到期时,系统会调用该回调函数,用于响应定时器的到期事件。
    data,function回调函数的参数。
    slack,对有些对到期时间精度不太敏感的定时器,到期时刻允许适当的延迟一小段时间。该字段用于计算每次延迟的HZ数。
    3.1.5.2 定义timer_list
      要定义一个定时器,可以使用静态动态两种方案。静态方案使用DEFINE_TIMER宏,代码如下:
    #define DEFINE_TIMER(_name, _function, _expires, _data)
       该宏将得到一个名字为_name,回调函数为_function,回调函数参数为_data,到期时刻为_expires的timer_list结构。

      如果使用动态方法,可以自己声明一个timer_list结构,之后手动初始化其相关字段,代码如下:
    struct timer_list timer;
    init_timer(&timer);
    timer.function=_function;
    timer.expires=_expires;
    timer.data=_data;
    3.1.5.3 激活定时器
      可以使用add_timer(&timer)激活一个定时器。
    3.1.5.4 修改定时器到期时间
      可以使用mod_timer(&timer, new_expires)修改定时器到期时间。
    3.1.5.5 移除定时器
      使用函数del_timer(&timer)移出定时器。
    3.1.5.6 延迟处理
      对于某些对精度不敏感的定时器,我们可以设定timer_list.slack字段的值,设定timer允许到期时刻的最大延迟。使用函数set_timer_slack(&timer, slack_hz)可以完成目标。

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|手机版|Archiver|Ubuntu Kylin    

    GMT+8, 2019-12-6 02:01 , Processed in 0.015905 second(s), 10 queries , File On.

    Copyright ©2013-2019 Ubuntu Kylin. All Rights Reserved .

    ICP No. 15002470-2 Tianjin

    快速回复 返回顶部 返回列表