Ubuntu Kylin技术论坛

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

linux时间子系统(九)

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

    [LV.6]常住居民II

    发表于 2018-8-8 16:51:00 | 显示全部楼层 |阅读模式
    3.4.3 模拟tick事件
          当系统切换到高精度模式后,tick_device被高精度定时器系统接管,不再定期地产生tick事件。内核在3.0.30版本中还没有彻底的废除jiffies机制,系统还是依赖定期到来的tick事件,完成进程调度和时间更新等操作,大量存在的低精度定时器仍然依赖于jiffies计数。所以,尽管tick_device被接管,高精度定时器系统仍然需要继续提供定期的tick事件。为了完成这个需求,由于高精度模式已经启用,内核定义了一个hrtimer,把它的到期时间设定为一个jiffy的时间,当着个hrtimer到期时,在这个hrtimer的到期函数中,进行和原来的tick_device同样的操作,然后把该hrtimer的到期时间顺延一个jiffy周期。如此反复循环,可以完美的模拟原有tick_device的功能。
         在kernel/time/tick-sched.c中,内核定义了一个per_cpu的全局变量:tick_cpu_sched,从而为每个cpu提供了一个tick_sched结构。该结构主要用于管理NO_HZ配置下的tickless处理,因为模拟tick事件与tickless有很强的相关性,所以高精度定时器也利用了该结构的以下字段,用来完成模拟tick时间的操作:

    struct tick_sched {
            struct hrtimer                  sched_timer;        /* 主要用于模拟tick时间的hrtimer。*/
            unsigned long                   check_clocks;        /* 第0位表明是否有符合要求的高精度定时器。*/
            enum tick_nohz_mode             nohz_mode;        /* 用于表示当前的工作模式。*/
    ......
    }
       内核使用函数tick_setup_sched_timer,该函数的作用就是设置一个用于模拟tick事件的hrtimer。
    void tick_setup_sched_timer(void)
    {
            struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
            ktime_t now = ktime_get();
            /*
             * Emulate tick processing via per-CPU hrtimers:
             */
            hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);        /* 初始化该cpu所属的tick_sched结构中的sched_timer字段。*/
            ts->sched_timer.irqsafe = 1;
            ts->sched_timer.function = tick_sched_timer;                /* 把该hrtimer的回调函数设置为tick_sched_timer.*/
            /* Get the next period (per cpu) */
            hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());        /* 设置到期时间为下一个jiffy时刻。*/
            for (;;) {
                    hrtimer_forward(&ts->sched_timer, now, tick_period);
                    hrtimer_start_expires(&ts->sched_timer,
                                          HRTIMER_MODE_ABS_PINNED);
                    /* Check, if the timer was already in the past */
                    if (hrtimer_active(&ts->sched_timer))
                            break;
                    now = ktime_get();
            }
    #ifdef CONFIG_NO_HZ
            if (tick_nohz_enabled) {
                    ts->nohz_mode = NOHZ_MODE_HIGHRES;                /* 将工作模式设置为NOHZ_MODE_HIGHRES模式,表明利用高精度模式实现NO_HZ。*/
                    printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
            }
    #endif
    }
    static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
    {               
            struct tick_sched *ts =
                    container_of(timer, struct tick_sched, sched_timer);
            struct pt_regs *regs = get_irq_regs();
            ktime_t now = ktime_get();
            int cpu = smp_processor_id();
            static int i=0;
    #ifdef CONFIG_NO_HZ
            /*
             * Check if the do_timer duty was dropped. We don't care about
             * concurrency: This happens only when the cpu in charge went
             * into a long sleep. If two cpus happen to assign themself to
             * this duty, then the jiffies update is still serialized by
             * xtime_lock.
             */
            if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
                    tick_do_timer_cpu = cpu;
    #endif
            /* Check, if the jiffies need an update */
            if (tick_do_timer_cpu == cpu)                        /* 在smp系统中,只有一个cpu负责jiffies计数,时间更新等全局操作。所以判定当前cpu
                                                               是否是负责更新jiffies和时间,如果是,则执行更新操作。*/
                    tick_do_update_jiffies64(now);
            /*
             * Do not call, when we are not in irq context and have
             * no valid regs pointer
             */
            if (regs) {                                                                /* 利用regs指针确保当前是在中断上下文,然后调用update_precess_timer。*/
                    /*
                     * When we are idle and the tick is stopped, we have to touch
                     * the watchdog as we might not schedule for a really long
                     * time. This happens on complete idle SMP systems while
                     * waiting on the login prompt. We also increment the "start of
                     * idle" jiffy stamp so the idle accounting adjustment we do
                     * when we go busy again does not account too much ticks.
                     */
                    if (ts->tick_stopped) {
                            touch_softlockup_watchdog();
                            ts->idle_jiffies++;
                    }
                    update_process_times(user_mode(regs));
                    profile_tick(CPU_PROFILING);
            }
            hrtimer_forward(timer, now, tick_period);        /* 把hrtimer的到期时间推进一个tick周期。*/
            return HRTIMER_RESTART;                        /*返回HRTIMER_RESTART表明该hrtimer需要再次启动,以便产生下一个tick事件。*/
    }
         对比模拟tick时间的hrtimer的回调函数tick_sched_timer和切换前tick_device的回调函数tick_handle_periodic,他们几乎完成了一样的工作。

    3.5 hrtimer的使用
         我们可以使用系统调用timer_create/timer_delete/timer_gettime/timer_settime设置精度达到ns的定时器。不过每个进程只能有一个。
         系统提供getitimer/setitimer系统调用,提供精度为us级别的定时器。

    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2018-12-17 23:59 , Processed in 0.017493 second(s), 10 queries , File On.

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

    ICP No. 15002470-2 Tianjin

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